52615


Win32APIのSHGetFileInfoで256x256アイコンを取得しているのですが、CDドライブでCDが256x256アイコンを持っていない場合、次のように左上に偏った画像のアイコンが取得されてしまい、表示上問題があります。

[![CD-Drive
Icons](https://i.stack.imgur.com/LqLCS.png)](https://i.stack.imgur.com/LqLCS.png)

次のようなコードで取得しています。

[code]

    // (NativeMethods省略)
    // var bitmaps = CreateFileIconCollectionExtra("F:\\", NativeMethods.FILE_ATTRIBUTE.FILE_ATTRIBUTE_DIRECTORY, 0); で呼び出し
    //
    public static List<BitmapSource> CreateFileIconCollectionExtra(string filename, NativeMethods.FILE_ATTRIBUTE attribute, ativeMethods.SHGFI flags)
    {
        NativeMethods.SHFILEINFO shinfo = new NativeMethods.SHFILEINFO();
        shinfo.szDisplayName = string.Empty;
        shinfo.szTypeName = string.Empty;
        IntPtr hImg = NativeMethods.SHGetFileInfo(filename, attribute, out shinfo, (uint)Marshal.SizeOf(typeof(NativeMethods.SHFILEINFO)), NativeMethods.SHGFI.SHGFI_SYSICONINDEX | flags);
        var bitmaps = new List<BitmapSource>();
        var shils = Enum.GetValues(typeof(NativeMethods.SHIL)).Cast<NativeMethods.SHIL>();
        foreach (var shil in shils)
        {
            int hResult = NativeMethods.SHGetImageList(shil, ref NativeMethods.IID_IImageList, out NativeMethods.IImageList imglist);
            if (hResult == NativeMethods.S_OK)
            {
                IntPtr hicon = IntPtr.Zero;
                imglist.GetIcon(shinfo.iIcon, (int)NativeMethods.ImageListDrawItemConstants.ILD_TRANSPARENT, ref hicon);
                if (hicon != IntPtr.Zero)
                {
                    BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(hicon, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                    bitmapSource?.Freeze();
                    NativeMethods.DestroyIcon(hicon);
                    bitmaps.Add(bitmapSource);
                }
            }
        }
        return bitmaps;
    }
    
[/code]

Q1.
256x256リソースがない場合には256x256アイコンを取得できないようにしたいのですが、256x256のアイコンリソースが存在するかを判別するにはどうしたらよいのでしょうか。

Q2.
今回の用途はドライブ限定ですので、既定のドライブアイコン(CDを入れていないときのアイコン)を取得することでも表示上の問題は回避できます。規定のドライブアイコンを取得する方法はありますでしょうか。

* * *

Windows10  
VisualStudio 2017 (15.9.6)  
.NET Framework 4.6.2


CC BY-SA 4.0
2019-02-05T06:35:52.673
52558
2019-02-08T00:13:57.020
14817
question
c# .net winapi
SHGetFileInfoで256x256アイコンを取得したときに左上に偏ったアイコンが取得されてしまうことがある問題


`SHGetFileInfo`/`SHGetImageList`/`GetIcon`ではなくて、`LoadLibraryEx`/`EnumResourceNames`/`FindResource`/`LoadResource`/`LockResource`を使う方が良さそうです。

以下は.exeファイルからアイコンを抽出して別ファイルに書き出すプログラムの解説です。  
[実行ファイルからアイコンを取り出す](https://hp.vector.co.jp/authors/VA016117/rsrc2icon.html)

> 実行ファイル内のアイコン  
>
> アイコンは、リソースデータとして実行ファイル内に入っています。基本的にアイコンファイルと同じデータが入っているだけなので、リソース内の位置を特定してファイルに保存するだけで可能です。
> ただし、アイコンは複数の大きさや色のデータを持つ事もあるので、それらをすべて集める必要があります。このように複数のデータを持つアイコンをグループアイコンと呼びます。このとき、１つしかデータを持たない場合にも、データが１つのグループアイコンとしてあつかわれています。  
>  次に、アイコンを保存する手順を示します。
>
>   1. 実行ファイルを読み込む〔LoadLibraryEx〕
>
>   2. グループアイコンを列挙する〔EnumResourceNames〕
>
>   3. グループアイコンに含まれているアイコンを集める  
>  〔FindResource、LoadResource、LockResource〕
>
>   4. それらをまとめてファイルに保存する〔WriteFile〕
>
>

同様の処理でライブラリ化したものがあって、これらです。  
[Extract icons from EXE or DLL
files](https://www.codeproject.com/Articles/26824/Extract-icons-from-EXE-or-
DLL-files),
[TsudaKageyu/IconExtractor](https://github.com/TsudaKageyu/IconExtractor)

[IconLib - Icons Unfolded (MultiIcon and Windows Vista
supported)](https://www.codeproject.com/Articles/16178/IconLib-Icons-Unfolded-
MultiIcon-and-Windows-Vista)

上記IconExtractorを使ったものと並行して、他にWin32APIを使わずに実現したという回答がある記事がこちらです。  
[Using a 256 x 256 Windows Vista icon in an
application](https://stackoverflow.com/q/220465/9014308)

* * *

**追記**  
アイコンファイル名およびアイコンインデックスの情報は、`SHGetFileInfo()` の `uFlags` パラメータに
`SHGFI_ICONLOCATION(0x000001000)` を指定することによって取得できるようです。

[SHGetFileInfoW function](https://docs.microsoft.com/en-
us/windows/desktop/api/shellapi/nf-shellapi-shgetfileinfow), [SHFILEINFOW
structure](https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/ns-
shellapi-_shfileinfow)

> SHGFI_ICONLOCATION(0x000001000)
>
>
> ファイルのアイコンハンドラのIExtractIcon::GetIconLocationメソッドによって返される、pszPathによって指定されたファイルを表すアイコンを含むファイルの名前を取得します。  
>  そのファイル内のアイコンインデックスも取得します。  
>  アイコンを含むファイルの名前は、psfiで指定された構造のszDisplayNameメンバーにコピーされます。  
>  アイコンのインデックスは、その構造体のiIconメンバーにコピーされます。

ご質問では、`SHGetFileInfo()` の `uFlags` パラメータに `SHGFI_SYSICONINDEX (0x000004000)`
を指定して、取得した `shinfo.iIcon` だけを使っていますが、今度は `shinfo.szDisplayName` も使う形になるでしょう。  
そして `SHGetFileInfo()` は残して、`GetValues()`/`SHGetImageList()`/`GetIcon()`
の代りに、`LoadLibraryEx()`/`EnumResourceNames()`/`FindResource()`/`LoadResource()`/`LockResource()`
を使うことになると思われます。

* * *

ちなみに、ドライブアイコンを変える方法は以下の2つがあるようです。

  * Drive.icoファイルを用意して、autorun.infで指定する。
  * レジストリでカスタマイズする

[How to Change Drive Icons in Windows](https://www.howtogeek.com/291674/how-
to-change-drive-icons-in-windows/)

* * *

ついでに、システムで使われるアイコン類が何処にあるかの記事。

[Where can I find the icons used for Music, Pictures, Videos etc. folders in
Win10?](https://superuser.com/q/1261331)

[Where to find most of Windows 10's native
icons?](https://www.digitalcitizen.life/where-find-most-windows-10s-native-
icons)

オマケで上記に紹介のあるダウンロードサイト  
[7 sites where you can download free desktop icons for Windows
10](https://www.digitalcitizen.life/5-locations-where-you-can-download-icons-
free)


CC BY-SA 4.0
2019-02-07T02:26:29.380
52615
2019-02-08T00:13:57.020
2019-02-08T00:13:57.020
26370
26370
52558
answer


たとえ画像がなくても256x256アイコンは強制的に生成される仕様ではないでしょうか？ なお、四角い外枠も含めてアイコンとして生成されていました。

[![画像の説明をここに入力](https://i.stack.imgur.com/C79p6.png)](https://i.stack.imgur.com/C79p6.png)


CC BY-SA 4.0
2019-02-07T22:48:39.357
52633
2019-02-07T22:48:39.357
4236
52558
answer