给定 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 为我们提供项目图标的系统图像列表索引。我们使用 SHGetFileInfo
做到了. SHGetFileInfo 函数 gets the icon by asking the shell namespace for the icon index in the system 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 命名空间中表示 item 的方式:
IShellFolder
:thing 所在的文件夹,以及- child
PIDL
:该文件夹中东西的 ID
从那里有ways to get the system image list index :
Int32 GetIconIndex(IShellFolder folder, PITEMID_CHILD childPidl)
{
//Note: I actually have no idea how to do this.
}
但是 IShellFolder 已经出来了;我们现在正在使用 IShellItem
从 Windows Vista 开始,IShellItem
变为 the preferred AP我用于导航 shell。必须在 was cumbersome, and error prone 附近保持 IShellFolder
+pidl
对的 Windows 95 时代 API .
问题变成了:如何处理它?特别是,如何获取项目的系统图像列表中的图像索引?查看它的方法,甚至没有办法获得它的绝对 pidl:
- BindToHandler:绑定(bind)到由处理程序 ID 值 (BHID) 指定的项的处理程序。
- 比较:比较两个 IShellItem 对象。
- GetAttributes:获取 IShellItem 对象的请求属性集。
- GetDisplayName:获取 IShellItem 对象的显示名称。
- GetParent:获取 IShellItem 对象的父对象。
我希望 Windows Property System ,可通过 IShellItem2
访问, 将具有与 shell 图像列表图标索引关联的属性。不幸的是,我没有看到:
- System.DescriptionID
- System.InfoTipText
- System.InternalName
- System.Link.TargetSFGAOFlagsStrings
- System.Link.TargetUrl
- System.NamespaceCLSID
- System.Shell.SFGAOFlagsStrings
提取图标的方式
有are many standard ways在 Windows Shell 命名空间中获取与 thing 相关的图片:
-
IExtractIcon
.返回一个HICON
。需要IShellFolder
+pidl。如果失败you can use SHDefExtractIcon -
SHDefExtractIcon
.返回一个HICON
。需要图标文件的完整路径 -
IThumbnailCache
.需要IShellItem
。返回缩略图,而不是图标 -
IShellImageFactory
.获取表示IShellItem
的位图
-
IThumbnailProvider
.IExtractImage
的 Windows Vista 替代品
-
IExtractImage
.需要IShellFolder
+pidl
。 -
SHGetFileInfo
.需要完整文件路径或绝对 pidl
都不是:
- 取一个 IShellItem
- 返回索引
最佳答案
基本上似乎没有任何简单的方法可以做到这一点。 API 中根本没有提供它。
在你的问题中你说 “但是 shell 支持文件系统中文件和文件夹之外的东西。”,这让我觉得你忽略了 SHGetFileInfo
实际上支持直接使用 PIDL(使用 SHGFI_PIDL
标志)- 因此它可以用于非文件系统对象。如果您仍然拥有完整的 PIDL,这是获取图标索引的最简单方法,否则类似这样的方法应该可以工作:
int GetIShellItemSysIconIndex(IShellItem* psi)
{
PIDLIST_ABSOLUTE pidl;
int iIndex = -1;
if (SUCCEEDED(SHGetIDListFromObject(psi, &pidl)))
{
SHFILEINFO sfi{};
if (SHGetFileInfo(reinterpret_cast<LPCTSTR>(pidl), 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX))
iIndex = sfi.iIcon;
CoTaskMemFree(pidl);
}
return iIndex;
}
或者使用 Raymond Chen 的建议:
int GetIconIndex(IShellItem item)
{
Int32 imageIndex;
PIDLIST_ABSOLUTE parent;
IShellFolder folder;
PITEMID_CHILD child;
//Use IParentAndItem to have the ShellItem
//cough up the IShellObject and child pidl it is wrapping.
(item as IParentAndItem).GetParentAndItem(out parent, out folder, out child);
try
{
//Now use IShellIcon to get the icon index from the folder and child
(folder as IShellIcon).GetIconOf(child, GIL_FORSHELL, out imageIndex);
}
finally
{
CoTaskMemFree(parent);
CoTaskMemFree(child);
}
return imageIndex;
}
罢工><罢工>罢工>
原来 IShellFolder
有时不支持 IShellIcon
。例如尝试浏览 zip 文件。发生这种情况时,IShellIcon
的 IShellFolder
的 QueryInterface
将失败。
shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE
然而 SHGetFileInfo
知道如何处理它。
所以最好不要尝试自己获取 IShellIcon
接口(interface)。将繁重的工作留给 SHGetFileInfo
(至少在 Microsoft 的某人记录如何使用 IShellIcon
之前)。
关于windows - 如何获取 IShellItem 的系统图像列表图标索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35497503/