• 締切済み

WinAPI SHGetFileInfoでICONファイル名の取得方法?

SHGetFileInfoでExplorerに表示されるICONのファイル名を取得したいのですが うまくいきません。 int main(int argc, char* argv[]) { SHFILEINFO sfi; ::CoInitialize(NULL); if(0 == ::SHGetFileInfo("C:\\hogehoge.txt", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICONLOCATION)) return -1; printf("Icon location file = %s\n", sfi.szDisplayName); return 0; } SHGFI_TYPENAMEを指定するとsfi.szTypeNameファイルタイプ名が入るのは確認できたのですが、SHGFI_ICONLOCATIONを指定してもsfi.szDisplayNameにアイコンファイル名が入ってくれません。(sfi.szDisplayName[0]='\0'で終わりになっている...) MSDNを見る限りはこれであっているようなのですが、正しい使い方を教えてください。

  • seata
  • お礼率25% (1/4)

みんなの回答

  • cocky
  • ベストアンサー率57% (232/402)
回答No.4

正直うちの環境(Win98 + VC++ 6.0SP4)でもうまく行かないときはあります。 ただし、SHGFI_ICONを指定しておけばとりあえずアイコンハンドルが手に入るため、それをそのままMFCのCImageListとかに保存してListViewに渡してやればアイコンは表示できてしまうので、実際問題としてあまり不都合は感じてません。 WindowsCEを引き合いに出したのは、一応ターゲットとなっているOSプラットフォームが書かれていなかったため、念のため、と思ったまでのことです。 一応MSDN Knowledge Baseで検索をかけた結果でも、特にWin32環境で制限やバグがあるような報告は上がってなかったので、SHGFI_ICONLOCATIONがうまく働かない原因はいまだ謎のままです。

seata
質問者

お礼

解決になりませんでしたが、お付き合いくださいましてありがとうございました。

  • cocky
  • ベストアンサー率57% (232/402)
回答No.3

ひょっとすると、SHGFI_ICONLOCATIONだけではだめで、SHGFI_ICONも一緒に指定しないとだめなのではないでしょうか。MSDNのドキュメントには記載がありませんが。 あと気になるのは、WindowsCE Ver.2.10以降ではSHGFI_ICONLOCATIONはサポートされない、とMSDNドキュメントにも書かれているので、環境によってはSHGFI_ICONLOCATIONが使えなくなっている可能性も考えられます。

seata
質問者

補足

たびたびお付き合いありがとうございます。 SHGFI_ICONも指定しましたが、だめでした。 CEとWin32を関連付ける意味が良く解かりませんが、 となるとCEでサポートされない多くのWin32APIも使用不能の可能性がありますね。 環境によりというのはありえるかもしれませんが、 cockyさんの環境では、あのコードで問題なく取得出来るのでしょうか?

  • cocky
  • ベストアンサー率57% (232/402)
回答No.2

一つ確認ですが、「c:\hogehoge.txt」というファイルはHDD上に実在しますか? もし実在しないのであれば、SHGFI_USEFILEATTRIBUTESも一緒に指定しないと、Windowsが実際に「c:\hogehoge.txt」の情報を読みに行ってしまい、ファイルが存在しないためにエラーになってしまいますから、szDisplayNameに情報が入らないのも当たり前だと思いますが。

seata
質問者

補足

たびたびすみません。 ファイルは実在します。SHGFI_USEFILEATTRIBUTESを指定しても同じでした。 パラメータに問題があるのかと思い、ファイルの種類も取得するように 改良してみました。 #include <windows.h> #include <shellapi.h> #include <stdio.h> int main(int argc, char* argv[]) { SHFILEINFO sfi; ::CoInitialize(NULL); if(0 == ::SHGetFileInfo(".pdf", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICONLOCATION | SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES)) return -1; printf("Icon location file = %s\n", sfi.szDisplayName); printf("Type name = %s\n", sfi.szTypeName); return 0; } 結果、 Icon location file = Type name = Adobe Acrobat文書 となりました。ファイルの種類は問題なく取得できるのですが、アイコンファイル名だけなぜかできないです。

  • cocky
  • ベストアンサー率57% (232/402)
回答No.1

他の拡張子のファイルでは試してみましたか? .txtのような拡張子だとアイコン情報がSystemImageListの中に入っていて、SHGFI_ICONLOCATIONを指定してもアイコンファイル名が出てこなかったように記憶してるんですが。

seata
質問者

補足

早速の回答ありがとうございます。 .txtではなく、.pdfにしてみましたAcrobatReaderの実行ファイルあたりが 返ってきてよさそうなのですが、結果は同じです。 SHGetFileInfo APIのドキュメントにも出てきますが、 SystemImageListというのが具体的にどのようなImageListなのか (シェルにキャッシュされているアイコンを集めたものか、shell32.dllあたり に格納されているシェル標準で持っているアイコンを集めたものか) よくわかっていません。 いろいろ検索して調べてみましたが、うまく行く例が見当たりません。 もし「こうすればうまく行く」みたいな例があると助かります。 すみません。

関連するQ&A

  • ファイルに関連付けられているアイコンについて

    ファイルに関連付けられているアイコン取得について質問です。 開発環境 OS:XP Visual Studio 2005 言語:C、C++ 調べると、SHGetFileInfo()を使ってアイコンを 取得出来るらしいのですが、 取得するアイコンではなく違うアイコンが取得(表示)されます。 架空のファイル名(実際にないファイル名)でやってみると、 同じアイコンが取得(表示)されます。 ●ソース ーーーーーーーーーーーーーーーーー //アイコン取得部分 SHGetFileInfo("C:/WINDOWS/notepad.exe", 0, &icon, sizeof(icon), SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON); //アイコン表示部分 DrawIcon(hdc, 10, 10, icon.hIcon); ーーーーーーーーーーーーーーーーー SHGetFileInfo()の戻り値は、「1」でした。 間違っている所があるのでしょうか?

  • C#でウィンドウのアイコン取得する方法

    タスクマネージャのアプリケーションタブに 起動しているアプリケーション名とアイコンが一覧で表示されている部分のように 小さいアイコンを取得したいんですがなかなかうまくいきません。 ファイルに紐付くアイコンと解釈していただいても構いません。 とりあえず、下記のWin32 APIの処理を利用してみましたが SHGetFileInfoだけしかうまくいきませんでした。 しかし、SHGetFileInfoも、アイコンは取得できますがこれはファイルに紐付くアイコンではなく 実行体(EXE)に紐付くアイコンで表示されてしまいました。 開いているウィンドウ情報からだと実行プロセスのEXEのパスしか分からないからです。 ★質問★: ファイルに紐付く小さいアイコンの取得方法を教えてください!できればサンプルソース込みだと助かります。 #region 小さいアイコンを取得するためのWin32 API(ファイルパスから) // SHGetFileInfo関数 [DllImport("shell32.dll")] private static extern IntPtr SHGetFileInfo( string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags); // SHGetFileInfo関数で使用するフラグ private const uint SHGFI_ICON = 0x100; // アイコン・リソースの取得 private const uint SHGFI_LARGEICON = 0x0; // 大きいアイコン private const uint SHGFI_SMALLICON = 0x1; // 小さいアイコン private const uint SHGFI_TYPENAME = 0x400;//ファイルの種類 // SHGetFileInfo関数で使用する構造体 private struct SHFILEINFO { public IntPtr hIcon; public IntPtr iIcon; public uint dwAttributes; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szDisplayName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string szTypeName; }; #endregion #region 小さいアイコンを取得するためのWin32 API(ウィンドウハンドルからその1) [DllImport("user32.dll", EntryPoint = "GetClassLong")] public static extern IntPtr GetClassLongPtr32(IntPtr hWnd, int nIndex); [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex); const int GCL_HICON = (-14); const int GCL_HICONSM = (-34); #endregion #region 小さいアイコンを取得するためのWin32 API(ウィンドウハンドルからその2) [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); public const int WM_GETICON = 0x7F; public const int WM_SETICON = 0x80; public const int ICON_SMALL = 0; public const int ICON_BIG = 1; #endregion

  • C# FTPサーバ アイコン取得

    FTPサーバからファイル名とアイコンを取得してListViewに表示させたいのですが アイコンの取得がうまくいきません。ファイル名のみは出来ました。 SHGetFileInfo("ftp://localhost/test.txt", 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON); みたいな感じで取得できないかと試してみましたが駄目でした。 詳しい方ご教授お願いします。

  • バイナリデータをテキストファイルに出力したい

    以下のソースファイル(test.c) が、 バイナリデータをテキストファイルに するものらしいのですが、 ファイル名(例えば bi.dat)を指定する方法が わかりません。 C++は勉強し始めたばかりで 詳しくありません。 よろしくお願い致します #include <stdio.h> int main( int argc, char *argv[]) { FILE *fpIn; FILE *fpOut; short snData; if( argc < 2) { printf("ファイル名を入れてください。"); return -1; } fpIn = fopen( "argv[1]" , "rb"); if( fpIn == NULL) { printf("入力ファイル %s を開けませんでした。", argv[1]); return -2; } fpOut = fopen( "output.txt", "w"); if( fpOut == NULL) { printf("出力ファイル output.txt を開けませんでした。"); fclose(fpIn); return -3; } while( fread( &snData, sizeof(short), 1, fpIn) == 1) { fprintf( fpOut, "%d\n", snData); }; fclose(fpIn); fclose(fpOut); return 0; }

  • SHGetFileInfoでアイコンが取得できない場合がある

    VC++にてエクスプローラもどきを作成しています。 ListViewへファイルアイコンを表示するために、 SHGetFileInfoを使用し、 // 大きいアイコンのハンドル取得 // fnameは拡張子だけの文字列です SHGetFileInfo( fname, NULL, &shfInfo, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES ); licon = shfInfo.hIcon; 上記のようにしてファイルアイコンを取得し、 CImageListへ追加した上で、描画しています。 そして、ダイアログのサイズが変更された際に、 OnSize関数にて、ListView内のアイコンを再度取得し、 再描画しているのですが、 何度もOnSizeで再描画を行っているうちに、 SHGetFileInfoにて取得したshfInfo.hIconが NULLになってしまいます。 一度、shfInfo.hIconがNULLになると、 何度、SHGetFileInfoを呼んでも、返ってくるhIconは 毎回NULLになってしまい、ListView内に アイコンが表示されません。 SHGetFileInfo関数を呼ぶ際の制約等があるのでしょうか?

  • C言語 複数指定したファイルの内容表示

    C言語の質問です。 「実行したファイル名を除いたコマンド ライン引数に、 複数個指定したすべてのファイルの内容を標準出力に表示する」 というプログラムを作成しようと思うのですが。。。 どうしても上手くいきません。 1つのファイルの内容を標準出力に表示するプログラムになってしまいます。 どなたかお力を貸してください。 ちなみに、私が作成したプログラムは、以下です。↓↓ #include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; int c; if(argc != 2) { return 1; } if((fp=fopen(argv[1], "r"))==NULL) { return 1; } while((c=fgetc(fp)) !=EOF) { fputc(c, stdout); } fclose(fp); return 0; }

  • 質問させてください(かなり長いです)

    int main(int argc,char *argv[]) { if(argc != 3){ char err_message[] = "ファイル名を指定して下さい、またはファイル名が多すぎる\n"; write(2,err_message, strlen(err_message)); exit(EXIT_FAILURE); } char *InFile = argv[1]; /*入力ファイル名設定*/ char *OutFile = argv[2]; /*出力ファイル名設定*/ myclass ob(InFile,OutFile); ob.open(); ob.main(); ob.close(); return(0); } このようなソースがありif(arg=!3)のところを実行して終了してしまいます。よくint main(int argc,char *argv[])という書き出しを見ますがmainの引数はどこで使われているのでしょうか。よろしければご教授ください。

  • ファイルコピープログラムについて

    まだC言語とか始めたばかりであまりよく分からないのですが、 今、ドラッグしたファイルをデスクトップにコピーするプログラムを作成してるのですが、少し困ったことになりました・・・・ 一応ファイルのコピーをデスクトップに作成はできるのですが、 何故か、作成されたファイルのサイズが2バイト程大きくなります・・・。 ファイルサイズを変えずにコピーする方法が分かりません・・・ ソースを張っておきますので、誰か解決策を教えていただけないでしょうか? #include <stdio.h> #include <windows.h> int main(int argc,char *argv[]) { FILE *fp,*copy; int buf; if(argc>1){ rename(argv[1],"DATA.bin"); fp=fopen("DATA.bin","rb"); copy=fopen("c:/xxx/yyy/Desktop/COPY.bin","wb"); while(1){ fread(&buf,sizeof(buf),1,fp); fwrite(&buf,sizeof(buf),1,copy); if(feof(fp)){ puts("OK"); fclose(fp); fclose(copy); rename("DATA.bin",argv[1]); rename("COPY.bin",argv[1]); exit(1); } } } return 0; }

  • ファイルポインタによるコアダンプの解決法

    タイトルの通りです。以下のプログラムを実行するとコアダンプがでるので、解決法を教えて頂きたいです。 5つのdatファイルの読み込みはうまくいきました。15個に増やしたところ、コアダンプが表示されました。 ファイルポインタを使わずに実行してみたら15個でも大丈夫でしたので、ファイルポインタが原因かと思います。 typedef struct{ int class; int** matrix; }pattern_struct; int main(int argc,char* argv[]) { pattern_struct *learn; FILE *fp; int width,height; int i,j,k,value; learn=(int*)malloc(argc*sizeof(int)); //ファイルからの学習データの読み込み for(k=1;k<argc;k++){ fp=fopen(argv[k],"r"); printf("%s\n",argv[k]); printf("学習する数字を入力してください "); scanf("%d",&learn[k].class); fscanf(fp,"%d %d",&width,&height); learn[k].matrix=(int**)malloc(height*sizeof(int*)); for(i=0;i<height;i++) learn[k].matrix[i]=(int*)malloc(width*sizeof(int)); for(i=0;i<height;i++){ for(j=0;j<width;j++){ fscanf(fp,"%d",&value); learn[k].matrix[i][j]=value; } } fclose(fp); fp=NULL; } return 0; }

  • 非常に基本的なポインタの使い方

    非常に基本的なところだと思いますが、ポインタの理解がうまくなく意図どおりのプログラムが書けません。 何らか引数を渡して(とりあえず文字列"hogehoge"を渡す)、そのポインタaをtest関数に渡して、ちゃんと"hogehoge"が渡っていれば「pass」と出力する 意図なんですが、どうもうまくいっていないようです。 ----------------------------- int test(char* a) { if(a == "hogehoge"){ printf("pass\n"); }else{ printf("ng\n"); } return 0; } int main(int argc, char* argv[]) { char* a = argv[0]; // "hogehoge"を渡しているとします。 test(a); return 0; } ----------------------------- 何がおかしいのか理解ができず、困っています。 ちなみに char* a = argv[0]; の箇所を単純に char* a = "hogehoge"; とした場合はうまくいくので、余計に混乱しております。 どなたか、正解例をご教授いただけませんでしょうか。