Слои оверлея

Если вы разбираетесь в программировании (C++ Builder, Delphi), возможно вы сможете помочь в устранении проблемных мест в программе

Модератор: motyara

Аватара пользователя
Max Diesel
Автор программы
Сообщения: 3274
Зарегистрирован: Пт окт 12, 2007 3:26 pm
Контактная информация:

Слои оверлея

Сообщение Max Diesel »

Разыскивается код на Delphi/C++Builder, позволяющий получить у системы оверлейные слои значков. Буду очень признателен за конкретную помощь по данному вопросу.
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Только что рылся в MSDN там что-то есть такое и такое.
Аватара пользователя
Max Diesel
Автор программы
Сообщения: 3274
Зарегистрирован: Пт окт 12, 2007 3:26 pm
Контактная информация:

Сообщение Max Diesel »

При моих умениях взаимодействия со специфическими MS-функциями ничего не получается...
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Объясните пожалуйста что конкретно нужно, а то я не понял смысла чего надо сделать. С оверлеями не работал и только понял из описания, что это маленький значок типа стрелочки, рисуемый поверх ярлыков, к примеру.
Аватара пользователя
Max Diesel
Автор программы
Сообщения: 3274
Зарегистрирован: Пт окт 12, 2007 3:26 pm
Контактная информация:

Сообщение Max Diesel »

Насколько мне известно, оверлейный слой работает именно по такому принципу - накладывается поверх какой-либо иконки. Если запросить у ОС индекс иконки файла, то иконка соответствующая индексу (расположенная в системном ImageList'е) не будет содержать оверлейных слоев. Если же запросить не индекс, а саму иконку (получить ее как объект), то ОС выдаст ее с уже наложенными оверлейными слоями (сейчас именно такой принцип и используется в программе). Меня интересует способ получения непосредственно чего-то вроде "индекса слоя". Было бы замечательно если бы некий код примера содержал следующие фазы:
1. получение индекса иконки файла (впрочем эта фаза-то у меня есть),
2. получение индекса оверлейного слоя для этого файла,
3. прорисовка результирующей иконки на canvas какого-либо объекта через функцию DrawIconEx или какую-либо другую (в данном случае можно было бы наложить оверлейный слой на любую другую иконку, индекс которой известен).
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Код: Выделить всё

код удалил. смотрите ниже
Последний раз редактировалось admini Ср дек 09, 2009 1:40 pm, всего редактировалось 2 раза.
Аватара пользователя
Max Diesel
Автор программы
Сообщения: 3274
Зарегистрирован: Пт окт 12, 2007 3:26 pm
Контактная информация:

Сообщение Max Diesel »

Первый вариант (при SHGFI_ADDOVERLAYS) как раз и использован в программе на данный момент - получение иконки с объединенными слоями. А вот насчет второго варианта проблема... переменная overlayIndex вместо номера иконки слоя получает значение -1. Возможно я при компиляции делаю что-то не так, но именно такой исход и получался у меня всегда ранее... Удается ли при тестировании получить другие результаты?
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

хммм. мистика какая то. дома код работает а на работе тоже возвращает -1, а SHGetIconOverlayIndex всегда какое-то странное значение - 8. погляжу еще в чем дело и можно уточнить а зачем разделять иконки и оверлеи когда сразу отрисовывать?
Аватара пользователя
Max Diesel
Автор программы
Сообщения: 3274
Зарегистрирован: Пт окт 12, 2007 3:26 pm
Контактная информация:

Сообщение Max Diesel »

Отделение иконки от оверлейного слоя нужно для случаев когда например установлены несистемные иконки каталогов, но при этом должны быть отображены оверлеи (чтобы не получалось месиво из иконок, ведь оверлейные слои всегда по умолчанию налагаются на системные иконки каталогов). Да и с точки зрения памяти явно рациональнее получать не готовую иконку как объект, а лишь однобайтовый индекс оверлейного слоя (да и с прорисовкой оверлейных иконок при входе в каталог получается не так как хотелось, ведь каждый раз производится перечитывание всех иконок без кэширования).

И кстати я обратил внимание на тот факт, что если пройтись по полученному ImageList'у напрямую (прорисовывать все иконки от нулевой по очереди), то необходимых оверлейных среди существующих нет (хотя некоторые другие оверлейные все-таки есть). Отсюда напрашивается вывод что может быть система выдает не системный ImageList, а какой-то его урезанный аналог?
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Код: Выделить всё

код удалил. смотрите ниже
Последний раз редактировалось admini Сб дек 12, 2009 1:23 pm, всего редактировалось 2 раза.
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Кстати информация - придурки из MS убрали оверлеи у расшаренных папок в Win7 и поэтому данная функа не работает для расшаренных папок (вернет -1) но анрил как то отрисовывает с объединенными оверлеями...
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Код: Выделить всё

код удалил. смотрите ниже
Последний раз редактировалось admini Сб дек 12, 2009 1:23 pm, всего редактировалось 1 раз.
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

В общем теперь всё работает. Если уже пробовали предыдущий код, то удалите его и пробуйте этот :)
Требования: Windows 2000 или выше и не забывать юзать CoInitializeEx где необходимо.

Код: Выделить всё

uses
  ActiveX, ShlObj, ShLwApi, CommCtrl;

const
  IID_IShellIconOverlay: TGUID = (
    D1:$7D688A70; D2:$C613; D3:$11D0; D4:($99, $9B, $00, $C0, $4F, $D6, $55, $E1));

  IID_IShellIconOverlayManager: TGUID = (
    D1:$F10B5E34; D2:$DD3B; D3:$42A7; D4:($AA, $7D, $2F, $4E, $C5, $4B, $B0, $9B));

  CLSID_CFSIconOverlayManager: TGUID = (
    D1:$63B51F81; D2:$C868; D3:$11D0; D4:($99, $9C, $00, $C0, $4F, $D6, $55, $E1));

type
  IShellIconOverlayManager = interface
    ['{F10B5E34-DD3B-42A7-AA7D-2F4EC54BB09B}']
    function GetFileOverlayInfo(pwszPath: LPCWSTR; dwAttrib: DWORD;
      var iIndex: Integer; dwFlags: DWORD): HRESULT; stdcall;
    function GetReservedOverlayInfo(pwszPath: LPCWSTR; dwAttrib: DWORD;
      var iIndex: Integer; dwFlags: DWORD; iReservedID: Integer): HRESULT; stdcall;
    function RefreshOverlayImages(dwFlags: DWORD): HRESULT; stdcall;
    function LoadNonloadedOverlayIdentifiers(): HRESULT; stdcall;
    function OverlayIndexFromImageIndex(iImage: Integer;
      var iIndex: Integer; fAdd: BOOL): HRESULT; stdcall;
  end;

const
  SIOM_OVERLAYINDEX      = 1;
  SIOM_ICONINDEX         = 2;
  SIOM_RESERVED_SHARED   = 0;
  SIOM_RESERVED_LINK     = 1;
  SIOM_RESERVED_SLOWFILE = 2;

const
  SHGFI_ICON              = $000000100;
  SHGFI_DISPLAYNAME       = $000000200;
  SHGFI_TYPENAME          = $000000400;
  SHGFI_ATTRIBUTES        = $000000800;
  SHGFI_ICONLOCATION      = $000001000;
  SHGFI_EXETYPE           = $000002000;
  SHGFI_SYSICONINDEX      = $000004000;
  SHGFI_LINKOVERLAY       = $000008000;
  SHGFI_SELECTED          = $000010000;
  SHGFI_LARGEICON         = $000000000;
  SHGFI_SMALLICON         = $000000001;
  SHGFI_OPENICON          = $000000002;
  SHGFI_SHELLICONSIZE     = $000000004;
  SHGFI_PIDL              = $000000008;
  SHGFI_USEFILEATTRIBUTES = $000000010;    
  SHGFI_ADDOVERLAYS       = $000000020;
  SHGFI_OVERLAYINDEX      = $000000040;

type
  _SHFILEINFOW = packed record
    hIcon: HICON;
    iIcon: Integer;
    dwAttributes: DWORD;
    szDisplayName: array [0..MAX_PATH-1] of  WideChar;
    szTypeName: array [0..79] of WideChar;            
  end;

function SHGetFileInfoW(pszPath: LPCWSTR; dwFileAttributes: DWORD;
  var psfi: _SHFILEINFOW; cbFileInfo, uFlags: UINT): DWORD; stdcall; external 'SHELL32.DLL';

function QueryShlObjIconOverlayIndex(filePath: PWideChar; var iIndex: Integer): Boolean;
var
  pathBuf: PWideChar;
  desktopFolder, folder: IShellFolder;
  folderID, fileID: PItemIDList;
  shellIconOverlay: IShellIconOverlay;
  overlayIndex, overlayIconIndex: Integer;
begin
  Result := False;
  iIndex := -1;
  if not PathFileExistsW(filePath) then Exit;
  GetMem(pathBuf, (lstrlenW(filePath) + 1) shl 1);
  try
    lstrcpyW(pathBuf, filePath);
    StrTrimW(pathBuf, '\');
    PathRemoveFileSpecW(pathBuf);
    SHGetDesktopFolder(desktopFolder);
    if not Assigned(desktopFolder) then Exit;     
    try
      desktopFolder.ParseDisplayName(0, nil,
        pathBuf, PULONG(nil)^, folderID, PULONG(nil)^);
      if not Assigned(folderID) then Exit;
      try
        desktopFolder.BindToObject(folderID, nil, IID_IShellFolder, folder);
        if not Assigned(folder) then Exit;
        try
          lstrcpyW(pathBuf, PathFindFileNameW(filePath));
          StrTrimW(pathBuf, '\');
          folder.ParseDisplayName(0, nil,
            pathBuf, PULONG(nil)^, fileID, PULONG(nil)^);
          if not Assigned(fileID) then Exit;
          try
            folder.QueryInterface(IID_IShellIconOverlay, shellIconOverlay);
            if not Assigned(shellIconOverlay) then Exit;
            try
              shellIconOverlay.GetOverlayIndex(fileID, overlayIndex);
              shellIconOverlay.GetOverlayIconIndex(fileID, overlayIconIndex);
              if (overlayIndex >= overlayIconIndex) then
                iIndex := overlayIndex - 1
              else
                iIndex := overlayIconIndex; 
            finally
              shellIconOverlay := nil;
            end;
          finally
            CoTaskMemFree(fileID);
          end;
        finally
          folder := nil;
        end;
      finally
        CoTaskMemFree(folderID);
      end;
    finally
      desktopFolder := nil;
    end;
  finally
    FreeMem(pathBuf);
  end;
  Result := True;
end;

function QueryReservedIconOverlayIndex(iReservedID: Integer; var iIndex: Integer): Boolean;
var
  shellIconOverlayManager: IShellIconOverlayManager;
begin
  Result := False;
  CoCreateInstance(CLSID_CFSIconOverlayManager, nil,
    CLSCTX_INPROC_SERVER, IID_IShellIconOverlayManager, shellIconOverlayManager);
  if not Assigned(shellIconOverlayManager) then Exit;
  try
    shellIconOverlayManager.GetReservedOverlayInfo(nil, 0, iIndex, SIOM_ICONINDEX, iReservedID);
  finally
    shellIconOverlayManager := nil;
  end;
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  filePath: WideString;
  shfi: _SHFILEINFOW;
  hImgList: integer;
  overlayIndex: Integer;
begin
  filePath := StringToOleStr(Edit1.Text);

  FillChar(shfi, SizeOf(shfi), 0);
  hImgList := SHGetFileInfoW(PWideChar(filePath), 0,
    shfi, SizeOf(shfi), SHGFI_SMALLICON or SHGFI_SYSICONINDEX or SHGFI_ATTRIBUTES);

  QueryShlObjIconOverlayIndex(PWideChar(filePath), overlayIndex);

  if (overlayIndex < 0) and (shfi.dwAttributes and SFGAO_SHARE <> 0) then
    QueryReservedIconOverlayIndex(SIOM_RESERVED_SHARED, overlayIndex);

  Refresh();
  ImageList_Draw(hImgList, shfi.iIcon, Canvas.Handle, 200, 100, ILD_TRANSPARENT);
  ImageList_Draw(hImgList, overlayIndex, Canvas.Handle, 200, 100, ILD_TRANSPARENT);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  FileInitIcons(True);
end;
Последний раз редактировалось admini Сб дек 12, 2009 1:23 pm, всего редактировалось 1 раз.
Аватара пользователя
Max Diesel
Автор программы
Сообщения: 3274
Зарегистрирован: Пт окт 12, 2007 3:26 pm
Контактная информация:

Сообщение Max Diesel »

Большое спасибо, код действительно работает так как надо. Весьма впечатляюще если учесть тот факт что прошла всего пара дней (я за гораздо больший период времени так и не смог разобраться в причине неотображения/неполучения оверлейных слоев).
admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

Re: Слои оверлея

Сообщение admini »

Я решил еще проанализировать ситуацию в плане документированности функций и рекомендаций из MSDN и оформить все в одном примере. Работает также начиная с вин2000. Думаю это наиболее подходящий вариант.
Вложения
SysImgList.rar
исходники
(158.83 КБ) 218 скачиваний
Закрыто