Слои оверлея

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

Модератор: motyara

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

Слои оверлея

Сообщение Max Diesel » Сб ноя 28, 2009 12:07 am

Разыскивается код на Delphi/C++Builder, позволяющий получить у системы оверлейные слои значков. Буду очень признателен за конкретную помощь по данному вопросу.

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Пт дек 04, 2009 8:34 pm

Только что рылся в MSDN там что-то есть такое и такое.

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

Сообщение Max Diesel » Вс дек 06, 2009 6:36 pm

При моих умениях взаимодействия со специфическими MS-функциями ничего не получается...

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Пн дек 07, 2009 9:53 am

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

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

Сообщение Max Diesel » Пн дек 07, 2009 7:04 pm

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

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Пн дек 07, 2009 11:50 pm

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

код удалил. смотрите ниже
Последний раз редактировалось admini Ср дек 09, 2009 1:40 pm, всего редактировалось 2 раза.

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

Сообщение Max Diesel » Вт дек 08, 2009 1:23 pm

Первый вариант (при SHGFI_ADDOVERLAYS) как раз и использован в программе на данный момент - получение иконки с объединенными слоями. А вот насчет второго варианта проблема... переменная overlayIndex вместо номера иконки слоя получает значение -1. Возможно я при компиляции делаю что-то не так, но именно такой исход и получался у меня всегда ранее... Удается ли при тестировании получить другие результаты?

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Вт дек 08, 2009 3:24 pm

хммм. мистика какая то. дома код работает а на работе тоже возвращает -1, а SHGetIconOverlayIndex всегда какое-то странное значение - 8. погляжу еще в чем дело и можно уточнить а зачем разделять иконки и оверлеи когда сразу отрисовывать?

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

Сообщение Max Diesel » Вт дек 08, 2009 3:36 pm

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

И кстати я обратил внимание на тот факт, что если пройтись по полученному ImageList'у напрямую (прорисовывать все иконки от нулевой по очереди), то необходимых оверлейных среди существующих нет (хотя некоторые другие оверлейные все-таки есть). Отсюда напрашивается вывод что может быть система выдает не системный ImageList, а какой-то его урезанный аналог?

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Вт дек 08, 2009 8:08 pm

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

код удалил. смотрите ниже
Последний раз редактировалось admini Сб дек 12, 2009 1:23 pm, всего редактировалось 2 раза.

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Ср дек 09, 2009 10:29 am

Кстати информация - придурки из MS убрали оверлеи у расшаренных папок в Win7 и поэтому данная функа не работает для расшаренных папок (вернет -1) но анрил как то отрисовывает с объединенными оверлеями...

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Ср дек 09, 2009 1:20 pm

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

код удалил. смотрите ниже
Последний раз редактировалось admini Сб дек 12, 2009 1:23 pm, всего редактировалось 1 раз.

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Ср дек 09, 2009 1:41 pm

В общем теперь всё работает. Если уже пробовали предыдущий код, то удалите его и пробуйте этот :)
Требования: 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
Автор программы
Сообщения: 3125
Зарегистрирован: Пт окт 12, 2007 9:00 pm
Контактная информация:

Сообщение Max Diesel » Ср дек 09, 2009 9:23 pm

Большое спасибо, код действительно работает так как надо. Весьма впечатляюще если учесть тот факт что прошла всего пара дней (я за гораздо больший период времени так и не смог разобраться в причине неотображения/неполучения оверлейных слоев).

admini
Охотник за багами
Сообщения: 21
Зарегистрирован: Чт фев 26, 2009 11:04 pm

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

Сообщение admini » Чт дек 10, 2009 12:29 am

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

Закрыто