如何获取系统镜像列表图标索引的IShellItem? [英] How to get system image list icon index of an IShellItem?

查看:493
本文介绍了如何获取系统镜像列表图标索引的IShellItem?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果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函数通过向系统imagelist中的图标索引询问shell命名空间来获取图标 a>:

  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支持除了文件系统中的文件和文件夹之外的其他内容。



来自IShellFolder的图标索引



在shell命名空间中获取对象信息的一般解决方案来自于使用在shell命名空间中表示的方式:




  • IShellFolder / li>
  • PIDL :该文件夹中 li>


获取系统映像列表索引的方法

  Int32 GetIconIndex(IShellFolder文件夹,PITEMID_CHILD childPidl)
{
//注意:我实际上不知道如何做到这一点。
}

但是IShellFolder现在正在使用IShellItem



从Windows Vista开始, IShellItem https://msdn.microsoft.com/en-us/library/windows/desktop/bb761144(v=vs.85).aspx\">首选AP 我用于导航shell。 Windows 95时代的API必须保持 IShellFolder + pidl blogs.msdn.microsoft.com/oldnewthing/20110831-00/?p=9763/\">麻烦,容易出错



问题变成了:如何做它的东西?特别是,我如何获得图像索引在系统图像列表中的项目?看看它的方法,甚至没有办法得到它的绝对pidl:




  • BindToHandler :绑定

  • 比较:比较两个IShellItem对象。

  • GetAttributes :获取IShellItem对象的一组请求属性。

  • GetDisplayName :获取IShellItem的显示名称对象。

  • GetParent :获取IShellItem对象的父对象。



我希望 Windows属性系统 ,可通过 IShellItem2 ,将具有与shell图像列表图标索引相关联的属性。很抱歉,我没有看到任何内容:





提取图标的方法 b
$ b

是许多标准方法获得与 em>在Windows Shell命名空间中:





不包括:




  • 取一个IShellItem

  • 返回索引


方案

基本上,似乎没有任何简单的方法。



在您的问题中,您说但是shell支持除文件系统中的文件和文件夹之外的事情。 / em>,这让我想你已经忽略了 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文件夹;
PITEMID_CHILD child;

//使用IParentAndItem使ShellItem
//咳嗽IShellObject和它包装的子pidl。
(item为IParentAndItem).GetParentAndItem(out parent,out folder,out child);
try
{
//现在使用IShellIcon从文件夹获取图标索引,子
(文件夹为IShellIcon).GetIconOf(child,GIL_FORSHELL,out imageIndex);
}
finally
{
CoTaskMemFree(parent);
CoTaskMemFree(child);
}

return imageIndex;
}



结果证明, IShellFolder 有时不支持 IShellIcon 。例如,尝试在zip文件中浏览。当发生这种情况时, IShellFolder QueryInterface

  shellFolder.QueryInterface(IID_IShellIcon,out shellIcon); //<  - 失败与E_NOINTERFACE 

SHGetFileInfo 知道如何处理它。



所以最好不要尝试自己得到一个 IShellIcon 接口。离开繁重的提升到 SHGetFileInfo (至少直到有人从Microsoft文档如何使用 IShellIcon )。


Given a Windows Vista or newer IShellItem, how do i get the system image list icon index associated with that item?

For example (pseudo-code):

IShellItem networkFolder = SHGetKnownFolderItem(FOLDERID_NetworkFolder, 0, 0, IShellItem);
Int32 iconIndex = GetSmallSysIconIndex(networkFolder);


Int32 GetSmallSysIconIndex(IShellItem item)
{
   //TODO: Ask Stackoverflow
}

Background

In the olden days (Windows 95 and newer), we could ask the shell to give us the system imagelist index for an item's icon. We did it using SHGetFileInfo. The SHGet­File­Info 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;
    }
}

That works when you are using an item in the shell namespace that corresponds to a file. But the shell supports things besides files and folders in the filesystem.

Icon Index from IShellFolder

The general solution for getting information about an object in the shell namespace comes from using the way you represent an item in the shell namespace:

  • IShellFolder: the folder that the thing sits in, along with
  • child PIDL: the id of the thing in that folder

From that there are 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.
}

But IShellFolder is out; we're using IShellItem now

Starting with Windows Vista, IShellItem became 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.

The question becomes: How to do stuff with it? In particular, how do i get the image index in the system image list of the item? Looking at its methods, there isn't even a way to get its absolute pidl:

  • BindToHandler: Binds to a handler for an item as specified by the handler ID value (BHID).
  • Compare: Compares two IShellItem objects.
  • GetAttributes: Gets a requested set of attributes of the IShellItem object.
  • GetDisplayName: Gets the display name of the IShellItem object.
  • GetParent: Gets the parent of an IShellItem object.

I was hoping that the Windows Property System, accessible through IShellItem2, would have a property associated with the shell imagelist icon index. Unfortunately, i don't see any:

Ways of extracting icons

There are many standard ways of getting the picture that goes with a thing in the Windows Shell Namespace:

None of them:

  • take an IShellItem
  • return an index

解决方案

Basically it doesn't seem that there's any easy method for this. It simply hasn't been provided in the API.

In your question you say "But the shell supports things besides files and folders in the filesystem.", which makes me think you have overlooked that SHGetFileInfo does actually support using PIDLs directly (with the SHGFI_PIDL flag) - so it can be used on non-filesystem objects. If you still have the full PIDL this is the easiest way to get an icon index, otherwise something like this should hopefully work:

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;
}

Or using Raymond Chen's suggestion:

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;
}

Turns out that IShellFolder doesn't support the IShellIcon sometimes. For example attempting to browse inside a zip file. When that happens, the QueryInterface of IShellFolder for IShellIcon fails.

shellFolder.QueryInterface(IID_IShellIcon, out shellIcon); //<--fails with E_NOINTERFACE

Yet SHGetFileInfo knows how to handle it.

So best to not try to get an IShellIcon interface yourself. Leave the heavy lifting to SHGetFileInfo (at least until someone from Microsoft documents how to use IShellIcon).

这篇关于如何获取系统镜像列表图标索引的IShellItem?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆