Windows 如何获取IShellItem的系统映像列表图标索引?
给定Windows Vista或更新版本的IShellItem,如何获取与该项目关联的系统映像列表图标索引 例如(伪代码): 背景 在过去(Windows95和更新版本),我们可以要求shell为我们提供项目图标的系统imagelist索引。我们是用电脑做的。SHGet-File-Info功能: 当您在shell名称空间中使用与文件对应的项时,该选项将起作用。但是shell除了支持文件系统中的文件和文件夹外,还支持其他功能 IShellFolder中的图标索引 获取shell名称空间中对象信息的一般解决方案来自使用在shell名称空间中表示项的方式:Windows 如何获取IShellItem的系统映像列表图标索引?,windows,shell,winapi,com,Windows,Shell,Winapi,Com,给定Windows Vista或更新版本的IShellItem,如何获取与该项目关联的系统映像列表图标索引 例如(伪代码): 背景 在过去(Windows95和更新版本),我们可以要求shell为我们提供项目图标的系统imagelist索引。我们是用电脑做的。SHGet-File-Info功能: 当您在shell名称空间中使用与文件对应的项时,该选项将起作用。但是shell除了支持文件系统中的文件和文件夹外,还支持其他功能 IShellFolder中的图标索引 获取shell名称空间中对象信息的
:物品所在的文件夹,以及IShellFolder
- child
:该文件夹中对象的idPIDL
IShellItem
就成了导航shell的工具。Windows95时代的API必须保留一个IShellFolder
+pidl
对
问题变成了:如何使用它?特别是,如何在项目的系统映像列表中获取映像索引?从它的方法来看,甚至没有一种方法可以获得它的绝对pidl:
- BindToHandler:绑定到由处理程序ID值(BHID)指定的项目的处理程序
- 比较:比较两个IShellItem对象
- GetAttributes:获取IShellItem对象的请求属性集
- GetDisplayName:获取IShellItem对象的显示名称
- GetParent:获取IShellItem对象的父对象
- 。返回一个
。需要HICON
+pidl。如果失败了IShellFolder
- 。返回一个
。需要图标文件的完整路径HICON
- 。需要
。返回缩略图,而不是图标IShellItem
- 。获取表示IShellItem的位图
- 。Windows Vista替换为
IExtractImage
- 。需要
+IShellFolder
pidl
- 。需要完整文件路径或绝对pidl
- 拿一个IShellItem
- 返回索引
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;
}
结果是,IShellFolder
有时不支持IShellIcon
。例如,尝试在zip文件中浏览。发生这种情况时,IShellIcon
的IShellFolder
的QueryInterface
将失败
shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE
shellFolder.QueryInterface(IID_IShellIcon,out shellIcon)// 在您伟大的调查中,您忘记了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;
使用IParentAndItem将IShellItem分解为IShellFolder和pidl。然后使用IShellIcon::GetIconOf.@RaymondChen当ShellFolder是zip外壳扩展名时,调用IShellFolder上的QueryInterface(IID\u ShellIcon)
会失败,因为E\u NOINTERFACE
。同时,使用SHGetFileInfo
和SHGetIDListFromObject
返回的绝对pidl确实能够返回图标索引。直接进入IShellIcon
糟糕的形式,最好依靠SHGetFileInfo
来完成所有这些边缘案例的繁重工作?SHGetFileInfo使用IExtractCon,这比IShellIcon效率低(但是,如果IShellIcon不可用,你别无选择)。我将把它交给Jonathan,因为他有我需要的那部分:SHGetIDListFromObject
。但是,如果我有了IShellFolder
和childPIDL
,那么直接转到IShellIcon
似乎是更好的方法。您还提供了IShellIcon
的正确且有效的示例用法。
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;
}
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;
}
shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE
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;