如何获取 IShellItem 的系统图像列表图标索引?
How to get system image list icon index of an IShellItem?
给定 Windows Vista 或更高版本 IShellItem
,我如何获取与该项目关联的系统图像列表图标索引?
例如(伪码):
IShellItem networkFolder = SHGetKnownFolderItem(FOLDERID_NetworkFolder, 0, 0, IShellItem);
Int32 iconIndex = GetSmallSysIconIndex(networkFolder);
Int32 GetSmallSysIconIndex(IShellItem item)
{
//TODO: Ask Whosebug
}
背景
在过去(Windows 95 和更高版本),我们可以要求 shell 为我们提供项目图标的系统图像列表索引。我们使用 SHGetFileInfo
. The SHGetFileInfo function 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 支持文件系统中除文件和文件夹之外的东西。
来自 IShell文件夹的图标索引
获取有关 shell 命名空间中对象信息的一般解决方案来自使用您在 shell 命名空间中表示 item 的方式:
IShellFolder
:事物所在的文件夹,以及
- 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.
}
但是我Shell文件夹不在了;我们现在使用 IShellItem
从 Windows Vista 开始,IShellItem
变成了 the preferred API for navigating the shell. The Windows 95 era API of having to keep an IShellFolder
+pidl
pair around was cumbersome, and error prone。
问题变成了:如何处理它?特别是,如何获取项目的系统图像列表中的图像索引?查看它的方法,甚至没有办法获得它的绝对 pidl:
- BindToHandler:绑定到由处理程序 ID 值 (BHID) 指定的项的处理程序。
- Compare: 比较两个 IShellItem 对象。
- GetAttributes:获取 IShellItem 对象的请求属性集。
- GetDisplayName: 获取 IShellItem 对象的显示名称。
- GetParent: 获取 IShellItem 对象的父对象。
我希望 Windows Property System, accessible through IShellItem2
有一个与 shell 图像列表图标索引关联的 属性。不幸的是,我没有看到:
- System.DescriptionID
- System.InfoTipText
- System.InternalName
- System.Link.TargetSFGAOFlagsStrings
- System.Link.TargetUrl
- System.NamespaceCLSID
- System.Shell.SFGAOFlagsStrings
提取图标的方法
在 Windows Shell 命名空间中 are many standard ways 获取与 thing 相关的图片:
IExtractIcon
. Returns an HICON
. Requires IShellFolder
+pidl. If it fails you can use SHDefExtractIcon
SHDefExtractIcon
。 Returns 一个 HICON
。需要图标文件的完整路径
IThumbnailCache
。需要 IShellItem
。 Returns 缩略图,不是图标
IShellImageFactory
。获取表示 IShellItem
的位图
IThumbnailProvider
。 Windows IExtractImage
的 Vista 替代品
IExtractImage
。需要 IShellFolder
+pidl
.
SHGetFileInfo
。需要完整的文件路径,或绝对 pidl
None 其中:
- 拿一个 IShellItem
- return一个索引
基本上似乎没有什么简单的方法可以做到这一点。它根本没有在 API.
中提供
在你的问题中你说 "But the shell supports things besides files and folders in the filesystem.",这让我觉得你忽略了 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 文件。发生这种情况时,IShellFolder
的 QueryInterface
for IShellIcon
会失败。
shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE
然而SHGetFileInfo
知道如何处理它。
所以最好不要尝试自己获取 IShellIcon
接口。将繁重的工作留给 SHGetFileInfo
(至少在 Microsoft 的某人记录如何使用 IShellIcon
之前)。
在你的伟大调查中,你忘记了 IShellIcon 接口。它甚至在 Windows XP 中可用。
function GetIconIndex(AFolder: IShellFolder; AChild: PItemIDList): Integer; overload;
var
ShellIcon: IShellIcon;
R: HRESULT;
begin
OleCheck(AFolder.QueryInterface(IShellIcon, ShellIcon));
try
R := ShellIcon.GetIconOf(AChild, 0, Result);
case R of
S_OK:;
S_FALSE:
Result := -1; // icon can not be obtained for this object
else
OleCheck(R);
end;
finally
ShellIcon := nil;
end;
end;
给定 Windows Vista 或更高版本 IShellItem
,我如何获取与该项目关联的系统图像列表图标索引?
例如(伪码):
IShellItem networkFolder = SHGetKnownFolderItem(FOLDERID_NetworkFolder, 0, 0, IShellItem);
Int32 iconIndex = GetSmallSysIconIndex(networkFolder);
Int32 GetSmallSysIconIndex(IShellItem item)
{
//TODO: Ask Whosebug
}
背景
在过去(Windows 95 和更高版本),我们可以要求 shell 为我们提供项目图标的系统图像列表索引。我们使用 SHGetFileInfo
. The SHGetFileInfo function 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 支持文件系统中除文件和文件夹之外的东西。
来自 IShell文件夹的图标索引
获取有关 shell 命名空间中对象信息的一般解决方案来自使用您在 shell 命名空间中表示 item 的方式:
IShellFolder
:事物所在的文件夹,以及- 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.
}
但是我Shell文件夹不在了;我们现在使用 IShellItem
从 Windows Vista 开始,IShellItem
变成了 the preferred API for navigating the shell. The Windows 95 era API of having to keep an IShellFolder
+pidl
pair around was cumbersome, and error prone。
问题变成了:如何处理它?特别是,如何获取项目的系统图像列表中的图像索引?查看它的方法,甚至没有办法获得它的绝对 pidl:
- BindToHandler:绑定到由处理程序 ID 值 (BHID) 指定的项的处理程序。
- Compare: 比较两个 IShellItem 对象。
- GetAttributes:获取 IShellItem 对象的请求属性集。
- GetDisplayName: 获取 IShellItem 对象的显示名称。
- GetParent: 获取 IShellItem 对象的父对象。
我希望 Windows Property System, accessible through IShellItem2
有一个与 shell 图像列表图标索引关联的 属性。不幸的是,我没有看到:
- System.DescriptionID
- System.InfoTipText
- System.InternalName
- System.Link.TargetSFGAOFlagsStrings
- System.Link.TargetUrl
- System.NamespaceCLSID
- System.Shell.SFGAOFlagsStrings
提取图标的方法
在 Windows Shell 命名空间中 are many standard ways 获取与 thing 相关的图片:
IExtractIcon
. Returns anHICON
. RequiresIShellFolder
+pidl. If it fails you can use SHDefExtractIconSHDefExtractIcon
。 Returns 一个HICON
。需要图标文件的完整路径IThumbnailCache
。需要IShellItem
。 Returns 缩略图,不是图标IShellImageFactory
。获取表示IShellItem
的位图
IThumbnailProvider
。 WindowsIExtractImage
的 Vista 替代品
IExtractImage
。需要IShellFolder
+pidl
.SHGetFileInfo
。需要完整的文件路径,或绝对 pidl
None 其中:
- 拿一个 IShellItem
- return一个索引
基本上似乎没有什么简单的方法可以做到这一点。它根本没有在 API.
中提供在你的问题中你说 "But the shell supports things besides files and folders in the filesystem.",这让我觉得你忽略了 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 文件。发生这种情况时,IShellFolder
的 QueryInterface
for IShellIcon
会失败。
shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE
然而SHGetFileInfo
知道如何处理它。
所以最好不要尝试自己获取 IShellIcon
接口。将繁重的工作留给 SHGetFileInfo
(至少在 Microsoft 的某人记录如何使用 IShellIcon
之前)。
在你的伟大调查中,你忘记了 IShellIcon 接口。它甚至在 Windows XP 中可用。
function GetIconIndex(AFolder: IShellFolder; AChild: PItemIDList): Integer; overload;
var
ShellIcon: IShellIcon;
R: HRESULT;
begin
OleCheck(AFolder.QueryInterface(IShellIcon, ShellIcon));
try
R := ShellIcon.GetIconOf(AChild, 0, Result);
case R of
S_OK:;
S_FALSE:
Result := -1; // icon can not be obtained for this object
else
OleCheck(R);
end;
finally
ShellIcon := nil;
end;
end;