文件图标的当前叠加层

时间:2014-07-05 21:08:29

标签: c# windows winapi icons shell32

我现在已经在互联网上搜索了大约5个小时,如果我能找到答案,我会被诅咒。我发现这个问题在我旅途中的多个地方都没有得到答复。

我愿意使用能够产生与文件当前图标叠加相关的远程信息的任何语言。下面的图片展示了我正在谈论的叠加。

Synchronizing

Complete

1 个答案:

答案 0 :(得分:0)

procedure GetOverlayIconInfo(const AFileName: UnicodeString; out AIconFileName: UnicodeString; out AIconIndex: Integer);
const
  sShellIconOverlayIdentifiers = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers';
  sShell32 = 'shell32.dll';
  sImageres = 'imageres.dll';

  procedure RegCheck(AStatus: DWORD);
  begin
    if AStatus = ERROR_SUCCESS then Exit;
    SetLastError(AStatus);
    RaiseLastOSError;
  end;

  function GetNextOverlayIconHandlerName(AKey: HKEY; AIndex: Integer): UnicodeString;
  var
    Status: DWORD;
    Len: DWORD;
  begin
    Len := 256;
    while True do
      begin
        SetLength(Result, Len - 1);
        Status := RegEnumKeyExW(AKey, AIndex, PWideChar(Result), Len, nil, nil, nil, nil);
        case Status of
          ERROR_SUCCESS:
            begin
              SetLength(Result, Len);
              Exit;
            end;
          ERROR_MORE_DATA: Len := Len * 2;
          ERROR_NO_MORE_ITEMS:
            begin
              Result := '';
              Exit;
            end
        else
          RegCheck(Status);
        end;
      end;
  end;

  function GetOverlayIconHandlerCLSID(AKey: HKEY; const AName: UnicodeString): TCLSID;
  var
    Key: HKEY;
    Status: DWORD;
    Len: DWORD;
    Size: DWORD;
    CLSID: UnicodeString;
  begin
    RegCheck(RegOpenKeyExW(AKey, PWideChar(AName), 0, KEY_READ, Key));
    try
      Len := 256;
      while True do
        begin
          SetLength(CLSID, Len);
          Size := Len * SizeOf(WideChar);
          Status := RegQueryValueExW(Key, nil, nil, nil, PByte(PWideChar(CLSID)), @Size);
          case Status of
            ERROR_SUCCESS:
              begin
                SetLength(CLSID, (Size div SizeOf(WideChar)) - 1);
                Result := StringToGUID(CLSID);
                Exit;
              end;
            ERROR_MORE_DATA: Len := (Size div SizeOf(WideChar));
          else
            RegCheck(Status);
          end;
        end;
    finally
      RegCloseKey(Key);
    end;
  end;

  procedure GetOverlayIconInfo(const AOverlayHandlerCLSID: TCLSID; out AIconFileName: UnicodeString; out AIconIndex: Integer);
  var
    Unknown: IUnknown;
    ShellIconOverlayIdentifier: IShellIconOverlayIdentifier;
    Flags: DWORD;
  begin
    OleCheck(CoCreateInstance(AOverlayHandlerCLSID, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, Unknown));
    try
      OleCheck(Unknown.QueryInterface(IID_IShellIconOverlayIdentifier, ShellIconOverlayIdentifier));
      try
        SetLength(AIconFileName, MAX_PATH);
        AIconFileName[1] := #0;
        AIconIndex := 0;
        Flags := 0;
        OleCheck(ShellIconOverlayIdentifier.GetOverlayInfo(PWideChar(AIconFileName), Length(AIconFileName), AIconIndex, Flags));
        AIconFileName := PWideChar(AIconFileName);
        if Flags and ISIOI_ICONFILE <> 0 then
          begin
            if Flags and ISIOI_ICONINDEX = 0 then
              AIconIndex := 0;
          end
        else
          begin
            AIconFileName := '';
            AIconIndex := 0;
          end;
      finally
        ShellIconOverlayIdentifier := nil;
      end;
    finally
      Unknown := nil;
    end;
  end;

  function GetSystem32Dir: UnicodeString;
  begin
    SetLength(Result, MAX_PATH);
    OleCheck(SHGetFolderPathW(0, CSIDL_SYSTEM, 0, SHGFP_TYPE_CURRENT, PWideChar(Result)));
    Result := PWideChar(Result) + '\';
  end;

var
  FileInfo: TSHFileInfoW;
  OverlayIconIndex: Integer;
  Key: HKEY;
  Index: Integer;
  SubKeyName: UnicodeString;
  CLSID: TCLSID;
begin
  AIconFileName := '';
  AIconIndex := 0;

  // first off all we get overlay icon index of file
  ZeroMemory(@FileInfo, SizeOf(FileInfo));
  if SHGetFileInfoW(PWideChar(AFileName), 0, FileInfo, SizeOf(FileInfo), SHGFI_OVERLAYINDEX or SHGFI_ICON) = 0 then
    RaiseLastOSError;
  DestroyIcon(FileInfo.hIcon);
  OverlayIconIndex := (FileInfo.iIcon shr 24) and $0000000F;

  // now we enum all overlay icon handlers in the system
  if RegOpenKeyExW(HKEY_LOCAL_MACHINE, PWideChar(sShellIconOverlayIdentifiers), 0, KEY_READ, Key) = ERROR_SUCCESS then
    try
      Index := 0;
      while True do
        begin
          SubKeyName := GetNextOverlayIconHandlerName(Key, Index);
          if SubKeyName = '' then Break;

          try
            // create an instance of current overlay icon handler
            CLSID := GetOverlayIconHandlerCLSID(Key, SubKeyName);
            // and get information about overlay icon implemented by current overlay icon handler
            GetOverlayIconInfo(CLSID, AIconFileName, AIconIndex);
            // is our overlay icon implemented by current overlay icon handler?
            // if yes we found all information we are looking for
            if SHGetIconOverlayIndexW(PWideChar(AIconFileName), AIconIndex) = OverlayIconIndex then
              Exit;
          except
          end;

          Inc(Index);
        end;
    finally
      RegCloseKey(Key);
    end;

  // our overlay icon is not implemented by any of overlay icon handler
  // lets use heuristic
  AIconFileName := '';
  AIconIndex := 0;
  // I AM NOT FULLY SURE!!!
  case OverlayIconIndex of
    1: // share overlay
      begin
        if IsWindowsVistaOrLater then
          begin
            AIconFileName := GetSystem32Dir + sImageres;
            AIconIndex := 164;
          end
        else
          begin
            AIconFileName := GetSystem32Dir + sShell32;
            AIconIndex := 29;
          end;
      end;
    2: // link overlay
      begin
        if IsWindowsVistaOrLater then
          begin
            AIconFileName := GetSystem32Dir + sImageres;
            AIconIndex := 163;
          end
        else
          begin
            AIconFileName := GetSystem32Dir + sShell32;
            AIconIndex := 30;
          end;
      end;
    3: // default overlay
      begin
        if IsWindowsVistaOrLater then
          begin
            AIconFileName := GetSystem32Dir + sImageres;
            AIconIndex := 157;
          end
      end;
    4: // slow overlay
      begin
        if IsWindowsVistaOrLater then
          begin
            AIconFileName := GetSystem32Dir + sImageres;
            AIconIndex := 169; // NOT SURE!!!
          end
        else
          begin
            AIconFileName := GetSystem32Dir + sShell32;
            AIconIndex := 31;
          end;
      end;
  end;
end;