给定一个 Windows Vista 或更新版本的 IShellItem
,我该如何获取与该项关联的系统图像列表图标索引?
例如(伪代码):
IShellItem networkFolder = SHGetKnownFolderItem(FOLDERID_NetworkFolder, 0, 0, IShellItem);
Int32 iconIndex = GetSmallSysIconIndex(networkFolder);
Int32 GetSmallSysIconIndex(IShellItem item)
{
//TODO: Ask Stackoverflow
}
背景
在旧时代(Windows 95及以上版本),我们可以请求shell为项目的图标提供系统imagelist索引。我们使用SHGetFileInfo
实现。SHGetFileInfo函数通过询问shell命名空间获取系统imagelist中的图标索引来获取图标:
HICON GetIconIndex(PCTSTR pszFile)
{
SHFILEINFO sfi;
HIMAGELIST himl = SHGetFileInfo(pszFile, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX));
if (himl) {
return sfi.iIcon;
} else {
return -1;
}
}
当你在shell名称空间中使用对应文件的项时,它是可用的。但是,shell还支持文件系统以外的其他内容。
来自IShellFolder的图标索引
获取shell名称空间中对象信息的通用解决方案来自于使用在shell名称空间中表示项的方式:
IShellFolder
:包含事物的文件夹,以及- 子
PIDL
:该文件夹中事物的ID
从那里可以获取系统映像列表索引的方法:
Int32 GetIconIndex(IShellFolder folder, PITEMID_CHILD childPidl)
{
//Note: I actually have no idea how to do this.
}
但是IShellFolder已经过时了,现在我们在使用IShellItem
从Windows Vista开始,IShellItem
成为了导航Shell的首选API。在Windows 95时代,必须保留一个IShellFolder
+pidl
组合 非常繁琐且容易出错。
问题来了:如何处理它?特别是,如何获取该项在系统图像列表中的图像索引?查看其方法,甚至没有一种方法可以获取其绝对pidl:
- BindToHandler: 绑定到处理程序,根据处理程序ID值(BHID)指定项目的处理程序。
- Compare: 比较两个IShellItem对象。
- GetAttributes: 获取IShellItem对象的请求属性集。
- GetDisplayName: 获取IShellItem对象的显示名称。
- GetParent: 获取IShellItem对象的父级。
我希望通过Windows Property System,可通过IShellItem2
访问,与shell imagelist图标索引关联的属性。不幸的是,我没有看到任何属性:
- System.DescriptionID
- System.InfoTipText
- System.InternalName
- System.Link.TargetSFGAOFlagsStrings
- System.Link.TargetUrl
- System.NamespaceCLSID
- System.Shell.SFGAOFlagsStrings
提取图标的方法
在Windows Shell命名空间中,有许多标准方法可以获取与“thing”相关联的图片:
IExtractIcon
。返回一个HICON
。需要IShellFolder
+pidl。如果失败,可以使用SHDefExtractIconSHDefExtractIcon
。返回一个HICON
。需要图标文件的完整路径。IThumbnailCache
。需要IShellItem
。返回缩略图,而不是图标。IShellImageFactory
。获取表示IShellItem
的位图。IThumbnailProvider
。Windows Vista替代IExtractImage
IExtractImage
。需要IShellFolder
+pidl
。SHGetFileInfo
。需要完整的文件路径或绝对pidl。
没有一个:
- 使用 IShellItem
- 返回索引
QueryInterface(IID_ShellIcon)
会失败并返回E_NOINTERFACE
。同时,使用由SHGetIDListFromObject
返回的绝对pidl的SHGetFileInfo
确实能够返回图标索引。直接访问IShellIcon
是否不好,最好依赖于SHGetFileInfo
来处理所有这些边缘情况的繁重工作? - Ian Boyd