Как получить индекс значка списка системных изображений 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 и новее)мы могли бы попросить оболочку дать нам индекс системного imagelist для значка элемента. Мы сделали это с помощью SHGetFileInfo
. Функция SHGetFileInfo получает значок, задавая пространство имен оболочки для индекса значка в системном 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;
}
}
это работает, когда вы используете элемент в пространстве имен оболочки, что соответствует файл. Но оболочка поддерживает все кроме файлов и папок в файловой системе.
значок индекса из IShellFolder
общее решение для получения информации об объекте в пространстве имен оболочки происходит от использования способа представления элемент в пространстве имен оболочки:
-
IShellFolder
: папки, что вещь сидит вместе с -
ребенок
PIDL
: идентификатор вещь в папке
что есть способы получить индекс списка изображений системы:
Int32 GetIconIndex(IShellFolder folder, PITEMID_CHILD childPidl)
{
//Note: I actually have no idea how to do this.
}
но IShellFolder отсутствует; мы используем IShellItem теперь
начиная с Windows Vista,IShellItem
стало предпочтительный API для навигации по оболочке. Windows 95 era API, чтобы сохранить IShellFolder
+pidl
пара был громоздким и подвержен ошибкам.
возникает вопрос: как с ним что-то делать? В частности, как получить индекс изображения в списке системных изображений элемента? Глядя на его методы, нет даже способа получить его Абсолют pidl:
- BindToHandler: привязывается к обработчику для элемента, как указано значением идентификатора обработчика (BHID).
- сравнить: сравнивает два объекта IShellItem.
- методы getattributes: возвращает запрошенный набор атрибутов объекта IShellItem.
- GetDisplayName: возвращает отображаемое имя объекта IShellItem.
- GetParent: получает родитель объекта IShellItem.
я надеялся, что Система Свойств Windows, можно через IShellItem2
, будет иметь свойство, связанное с индексом значка оболочки imagelist. К сожалению, я не вижу любой:
- .DescriptionID
- .InfoTipText
- .InternalName
- .Ссылка на сайт.TargetSFGAOFlagsStrings
- .Ссылка на сайт.TargetUrl
- .NamespaceCLSID
2 ответов
в основном кажется, что для этого нет простого метода. Он просто не был предоставлен в API.
в вашем вопросе вы говорите "но оболочка поддерживает все кроме файлов и папок в файловой системе.", что заставляет меня думать, что вы упустили это SHGetFileInfo
фактически поддерживает использование PIDLs напрямую (с помощью SHGFI_PIDL
флаг) - так это can используется для объектов, отличных от файловой системы. Если у вас все еще есть полный 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;
}
или используя предложение Раймонда Чена:
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-файла. Когда это происходит,QueryInterface
of IShellFolder
на 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;