How to get the shell image index of an object in t

2019-09-21 14:54发布

I want to get the index in the system imagelist of an object in the shell namespace.

If this object was a file i could use SHGetFileInfo:

function GetFileImageIndex(const Filename: string): Integer;
var
   sfi: TSHFileInfo;
begin
   SHGetFileInfo(PChar(Filename), FILE_ATTRIBUTE_NORMAL, sfi, SizeOf(sfi), 
         SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX);
   Result := sfi.iIcon;
end;

Except i don't have a file

The thing i have doesn't exist on the hard-drive as a folder or file, e.g.:

  • Control Panel
  • Homegroup
  • Network

But i still need to get the index in the system imagelist of the icon that corresponds to this thing. I started with SHGetFileInfo (as it supports pidls). But that fell apart. Then i tried using IExtractIcon, but that fell apart:

function GetObjectImageIndex(ParentFolder: IShellFolder; const ChildPidl: PItemIDList): Integer;
//var
//  sfi: TSHFileInfo;

//  extractIcon: IExtractIcon;
//  iconFile: WideString;
//  iconIndexInFile: Integer;
//  flags: Cardinal;
begin
    {
        This function is the shell namespace equivalent of GetFileImageIndex helper function.
    }
(*
    Won't work (MSDN: "The PIDL must be a fully qualified PIDL. Relative PIDLs are not allowed.")
    SHGetFileInfo(PWideChar(ChildPidl), FILE_ATTRIBUTE_NORMAL,
            sfi, SizeOf(sfi),
            SHGFI_PIDL or SHGFI_SYSICONINDEX);
*)

(*
    Won't work. Doesn't return an index into the system imagelist
    ParentFolder.GetUIObjectOf(0, 1, ChildPidl, IExtractIcon, nil, {out}extractIcon);
    SetLength(iconFile, MAX_PATH);
    extractIcon.GetIconLocation(0, PWideChar(iconFile), Length(iconFile), iconIndexInFile, {out}flags);
*)

    Result := -1; //TODO: Figure out how to do it.
end;

Given an IShellFolder and a pidl in that folder, how do i get the icon in the system imagelist of that thing?

标签: shell delphi
2条回答
萌系小妹纸
2楼-- · 2019-09-21 15:20
function CreateGlobalChildIDList(AParentFolder: IShellFolder; const AChildIDList: PItemIDList): PItemIDList; forward;

function GetObjectImageIndex(AParentFolder: IShellFolder; const AChildIDList: PItemIDList): Integer;
var
  ShellIcon: IShellIcon;
  ChildIDList: PItemIDList;
  FileInfo: TSHFileInfo;
begin
  try
    Result := -1;
    try
      OleCheck(AParentFolder.QueryInterface(IShellIcon, ShellIcon));
      try
        OleCheck(ShellIcon.GetIconOf(AChildIDList, GIL_FORSHELL, Result));
      finally
        ShellIcon := nil;
      end;
    except
      Result := -1;
    end;

    if Result = -1 then
      begin
        ChildIDList := CreateGlobalChildIDList(AParentFolder, AChildIDList);
        try
          ZeroMemory(@FileInfo, SizeOf(FileInfo));
          SHGetFileInfo(PWideChar(ChildIDList), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo), SHGFI_PIDL or SHGFI_SYSICONINDEX);
          Result := FileInfo.iIcon;
        finally
          CoTaskMemFree(ChildIDList);
        end;
      end;
  except
    Result := -1;
  end;
end;

  function CretaeGlobalChildIDList(AParentFolder: IShellFolder; const AChildIDList: PItemIDList): PItemIDList;
  var
    PersistFolder2: IPersistFolder2;
    PersistIDList: IPersistIDList;
    ParentIDList: PItemIDList;
  begin
    if Succeeded(AParentFolder.QueryInterface(IPersistFolder2, PersistFolder2)) then
      try
        OleCheck(PersistFolder2.GetCurFolder(ParentIDList));
        try
          Result := ILCombine(ParentIDList, AChildIDList);
        finally
          CoTaskMemFree(ParentIDList);
        end;
      finally
        PersistFolder2 := nil;
      end
    else
      if Succeeded(AParentFolder.QueryInterface(IPersistIDList, PersistIDList)) then
        try
          OleCheck(PersistIDList.GetIDList(ParentIDList));
          try
            Result := ILCombine(ParentIDList, AChildIDList);
          finally
            CoTaskMemFree(ParentIDList);
          end;
        finally
          PersistIDList := nil;
        end
      else
        raise Exception.Create('Cannot create PIDL');
  end;
查看更多
一纸荒年 Trace。
3楼-- · 2019-09-21 15:39

The simple answer is that you pass an absolute PIDL that identifies the object to SHGetFileInfo. You say you tried that without success, but this is the way to solve your problem.

You should go back to SHGetFileInfo and make it work. It looks like you got as far as having a relative PIDL and stopped. Make an absolute PIDL with ILCombine and you should be home.

If you don't have a PIDL for the containing IShellFolder then you'll want to read this topic: How to obtain the PIDL of an IShellFolder

查看更多
登录 后发表回答