Ian*_*oyd 8 windows com shell winapi
给定Windows Vista或更新版本IShellItem
,如何获取与该项目关联的系统映像列表图标索引?
例如(伪代码):
IShellItem networkFolder = SHGetKnownFolderItem(FOLDERID_NetworkFolder, 0, 0, IShellItem);
Int32 iconIndex = GetSmallSysIconIndex(networkFolder);
Int32 GetSmallSysIconIndex(IShellItem item)
{
//TODO: Ask Stackoverflow
}
Run Code Online (Sandbox Code Playgroud)
在过去的日子里(Windows 95和更新版本),我们可以要求shell为项目的图标提供系统图像列表索引.我们用它做了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;
}
}
Run Code Online (Sandbox Code Playgroud)
当您在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.
}
Run Code Online (Sandbox Code Playgroud)
但是IShellFolder已经出局了; 我们现在正在使用IShellItem
从Windows Vista开始,IShellItem
成为导航shell 的首选AP.必须保持IShellFolder
+ pidl
对的Windows 95时代API 很麻烦,而且容易出错.
问题变成:怎么做它的东西?特别是,如何在项目的系统图像列表中获取图像索引?看看它的方法,甚至没有办法获得它的绝对pidl:
我希望通过它可访问的Windows Property SystemIShellItem2
具有与shell imagelist图标索引相关联的属性.不幸的是,我没有看到任何:
提取图标的方法
有很多标准的方式获得该用那张图片的事情在Windows Shell中的命名空间:
IExtractIcon
.返回一个HICON
.需要IShellFolder
+ pidl.如果失败,您可以使用SHDefExtractIconSHDefExtractIcon
.返回一个HICON
.需要图标文件的完整路径IThumbnailCache
.需要IShellItem
.返回缩略图,而不是图标IShellImageFactory
.获取一个代表一个的位图IShellItem
IThumbnailProvider
.Windows Vista的替代品IExtractImage
IExtractImage
.需要IShellFolder
+ pidl
.SHGetFileInfo
.需要完整的文件路径或绝对的pidl他们都没有:
基本上似乎没有任何简单的方法可以做到这一点。它只是没有在 API 中提供。
在您的问题中,您说“但外壳支持文件系统中的文件和文件夹之外的内容。” ,这让我认为您忽略了 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;
}
Run Code Online (Sandbox Code Playgroud)
或者使用 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;
}
Run Code Online (Sandbox Code Playgroud)
事实证明,有时IShellFolder
不支持IShellIcon
。例如,尝试浏览 zip 文件。当这种情况发生时,QueryInterface
中IShellFolder
为IShellIcon
失败。
shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE
Run Code Online (Sandbox Code Playgroud)
却SHGetFileInfo
知道如何处理。
所以最好不要尝试自己获取IShellIcon
接口。将繁重的工作留给SHGetFileInfo
(至少在 Microsoft 的某个人文档如何使用 之前IShellIcon
)。
归档时间: |
|
查看次数: |
874 次 |
最近记录: |