LoginSignup
1
0

More than 5 years have passed since last update.

SHGetFileInfoで手に入れたHIMAGELISTはImageList_Destroyで開放するべからず

Last updated at Posted at 2018-04-05

注意

筆者はSHGetFileInfo関数を使ったことがありません。なのにそれについての記事を書きます、あれ?

発端

たまたまこのツイートが目に入った。

SHGetFileInfo
DWORD_PTR SHGetFileInfo(
  _In_    LPCTSTR    pszPath,
          DWORD      dwFileAttributes,
  _Inout_ SHFILEINFO *psfi,
          UINT       cbFileInfo,
          UINT       uFlags
);

この関数を使って大きいサイズ(48 x 48)のアイコンを取得する方法がある(後述)。
SHGFI_SYSICONINDEXフラグを渡して戻り値をHIMAGELISTにキャストしてゴニョゴニョするとHICONが得られるのですが、このHIMAGELISTはどう後始末すればいいのでしょうか?

一般的なHIMAGELISTの扱い方

ImageList_Createで確保してImageList_Destroyで開放という流れです。

SHGetFileInfoで手に入れたHIMAGELISTImageList_Destroyで開放するべからず

ところでSHGetFileInfoのMSDNをよく見ると

Note
Once you have a handle to a system image list, you can use the Image List API to manipulate it like any other image list. Because system image lists are created on a per-process basis, you should treat them as read-only objects. Writing to a system image list may overwrite or delete one of the system images, making it unavailable or incorrect for the remainder of the process.

とあります。つまり

  • プロセスごとにimage listが生成される
  • SHGetFileInfoはそれへのポインタ
  • だからRead-Onlyで扱う
  • 変更操作をしたら同じプロセスからの以降の操作はどうなっても知らんよ

ということで、結論としてはImageList_Destroyで開放するべからず、となります。

サンプルコード

動作未検証。

#include <windows.h>
#include <Shellapi.h>
#include <Commctrl.h>
enum class IconSize : unsigned int {
    Large = 0,//SHGFI_LARGEICON 
    Small = 1,//SHGFI_SMALLICON
    ExtraLarge = 2,
};
HICON GetIcon(const ITEMIDLIST* pidFIle, IconSize iconSize)
{
    SHFILEINFO sfi;
    HIMAGELIST hImgList = reinterpret_cast<HIMAGELIST>(::SHGetFileInfo(
        reinterpret_cast<LPCSTR>(pidFIle), 0, &sfi, sizeof(SHFILEINFO),
        SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_ICON | (static_cast<unsigned int>(iconSize) & 1u)
    ));
    return (IconSize::ExtraLarge == iconSizeType) ? 
        ImageList_GetIcon(hImgList, sfi.iIcon, ILD_TRANSPARENT)
        : sfi.iIcon;
}
HICON GetIcon(const char* path, IconSize iconSizeType)
{
    SHFILEINFO sfi;
    HIMAGELIST hImgList = reinterpret_cast<HIMAGELIST>(::SHGetFileInfo(
        path, 0, &sfi, sizeof(SHFILEINFO),
        SHGFI_SYSICONINDEX | SHGFI_ICON | (static_cast<unsigned int>(iconSize) & 1u)
    ));
    return (IconSize::ExtraLarge == iconSizeType) ? 
        ImageList_GetIcon(hImgList, sfi.iIcon, ILD_TRANSPARENT)
        : sfi.iIcon;
}

参考サイト

License

CC BY 4.0

CC-BY icon.svg

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0