注意
筆者はSHGetFileInfo
関数を使ったことがありません。なのにそれについての記事を書きます、あれ?
発端
SHGetFileInfo で取得した HIMAGELIST って、解放せんでええのか?
— そらみみ (@soramimi_jp) 2018年4月5日
たまたまこのツイートが目に入った。
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 で確保した HIMAGELIST は ImageList_Destroy で解放するってのはわかるけど、SHGetFileInfo が返した HIMAGELIST は解放していいのかなぁ?
— そらみみ (@soramimi_jp) 2018年4月5日
ImageList_Create
で確保してImageList_Destroy
で開放という流れです。
SHGetFileInfo
で手に入れたHIMAGELIST
はImageList_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;
}
参考サイト
- ファイルアトリビュート|kab-studio
- Delphi システムイメージリストから任意サイズのアイコンを取得する
- プログラミングTips : ファイルの大きなアイコンを取得する
- SHGetFileInfo function (Windows)
- ImageList_GetIcon function (Windows)
- ImageList_Destroy function (Windows)
- SHFILEINFO structure (Windows)
- IMAGELISTDRAWFLAGS (Windows)
- winapi - Who is responsible for clearing up memory from image lists? - Stack Overflow