
Работа с иконками файлов на Ассемблере

Работа с иконками файлов на Ассемблере
Я уже рассказывал, как можно получить иконку из окна чужого приложения, сегодня тема будет похожей. Разница в том, что иконку мы будем получать из файла на диске. Применений для этого может быть много, например, чтобы отрисовать в вашем приложении красивый список файлов, нарисовать всплывающее меню, заменить иконку в собранном джойнере или патче. Для работы с иконками в WInAPI есть несколько функций, каждая со своими особенностями. В этой статье я попытаюсь подробно рассказать о них.
Первая функция - ExtractIcon, она по индексу извлекает иконку из исполняемого файла, динамической библиотеки или файла иконки. С ее же помощью можно узнать количество иконок в файле. Главный недостаток использования ExtractIcon заключается в том, что извлекаются только большие иконки 32х32, если значок, находящийся по запрошенному индексу, имеет другой размер, то он будет отмасштабирован.
Code (Assembler) : Убрать нумерацию
- ...
- fname db 'source.exe',0
- ...
- invoke GetModuleHandle,NULL
- mov ebx,eax
- invoke ExtractIcon,ebx,fname,0
- ; EAX - хэндл первой иконки
- invoke ExtractIcon,ebx,fname,1
- ; EAX - хэндл второй иконки
Code (Assembler) : Убрать нумерацию
- ...
- fname db 'source.exe',0
- hIconLarge dd ?
- hIconSmall dd ?
- arrSmall rd 4
- ...
- ; Извлечь по одной большой и маленькой иконке с индексом 0
- invoke ExtractIconEx,fname,0,hIconLarge,hIconSmall,1
- ; [hIconLarge] - хэндл большой иконки
- ; [hIconSmall] - хэндл маленькой иконки
- ; Извлечь из файла только маленькие иконки в количестве 4 штук,
- ; начиная с индекса 0 и до 3
- invoke ExtractIconEx,fname,0,NULL,arrSmall,4
- ; [arrSmall] - массив с четырьмя хэндлами маленьких иконок
Code (Assembler) : Убрать нумерацию
- ; Получить системные размеры больших и маленьких иконок
- invoke GetSystemMetrics,SM_CXICON
- ; EAX = ширина большой иконки
- invoke GetSystemMetrics,SM_CYICON
- ; EAX = высота большой иконки
- invoke GetSystemMetrics,SM_CXSMICON
- ; EAX = ширина маленькой иконки
- invoke GetSystemMetrics,SM_CYSMICON
- ; EAX = высота маленькой иконки
Code (Assembler) : Убрать нумерацию
- ...
- fname db 'source.exe',0
- hIcon dd ?
- tmp dd ?
- ...
- ; Загрузить иконки разных размеров
- invoke PrivateExtractIcons,fname,0,24,24,hIcon,tmp,1,LR_LOADTRANSPARENT
- ; [hIcon] - хэндл загруженной иконки
- invoke PrivateExtractIcons,fname,2,64,64,hIcon,tmp,1,LR_LOADTRANSPARENT
- invoke PrivateExtractIcons,fname,3,256,256,hIcon,tmp,1,LR_LOADTRANSPARENT
- ; Иконка несуществующего размера 22х60
- invoke PrivateExtractIcons,fname,1,22,60,hIcon,tmp,1,LR_LOADTRANSPARENT
- ; [hIcon] - хэндл загруженной иконки
Code (Assembler) : Убрать нумерацию
- ; Загрузить модуль с иконками
- invoke LoadLibrary,fname
- invoke LoadIconWithScaleDown,eax,1,64,64,hIcon
- ; [hIcon] - хэндл загруженной иконки
- ; Загрузить стандартную иконку щита UAC размером 16х16
- IDI_SHIELD = 0x7F06
- invoke LoadIconWithScaleDown,0,IDI_SHIELD,16,16,hIcon
- ; [hIcon] - хэндл загруженной иконки
Code (Assembler) : Убрать нумерацию
- struct SHFILEINFO
- hIcon dd ?
- iIcon dd ?
- dwAttributes dd ?
- szDisplayName rb MAX_PATH
- szTypeName rb 80
- ends
- SHGFI_ICON = 0x000000100
- SHGFI_SMALLICON = 0x000000001
- SHGFI_LARGEICON = 0x000000000
Code (Assembler) : Убрать нумерацию
- ...
- fname db 'source.exe',0
- fdir db 'c:\windows',0
- FileInfo SHFILEINFO
- ...
- invoke SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_LARGEICON
- ; [FileInfo.hIcon] - хэндл большой иконки, связанной с файлом
- invoke SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_SMALLICON
- ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с файлом
- ; Папка
- invoke SHGetFileInfo,fdir,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_LARGEICON
- ; [FileInfo.hIcon] - хэндл большой иконки, связанной с папкой
- invoke SHGetFileInfo,fdir,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_SMALLICON
- ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с папкой
Code (Assembler) : Убрать нумерацию
- ; GUID {93F2F68C-1D1B-11D3-A30E-00C04F79ABD1}
- IID_IShellFolder2 dd 093F2F68Ch
- dw 01D1Bh
- dw 011D3h
- db 0A3h, 00Eh, 000h, 0C0h, 04Fh, 079h, 0ABh, 0D1h
- ; GUID {000214FA-0000-0000-C000-000000000046}
- IID_IExtractIconW dd 0000214FAh
- dw 00000h
- dw 00000h
- db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
- ; IID_IShellFolder2 Interface
- struct IShellFolder2
- QueryInterface dd ?
- AddRef dd ?
- Release dd ?
- ; IShellFolder
- ParseDisplayName dd ?
- EnumObjects dd ?
- BindToObject dd ?
- BindToStorage dd ?
- CompareIDs dd ?
- CreateViewObject dd ?
- GetAttributesOf dd ?
- GetUIObjectOf dd ?
- GetDisplayNameOf dd ?
- SetNameOf dd ?
- ends
- ; IID_IExtractIconW Interface
- struct IExtractIcon
- QueryInterface dd ?
- AddRef dd ?
- Release dd ?
- GetIconLocation dd ?
- Extract dd ?
- ends
Code (Assembler) : Убрать нумерацию
- ...
- psfDesktop dd ?
- pidl dd ?
- appObject dd ?
- extractIcon dd ?
- pidlRelative dd ?
- iconLocation rw MAX_PATH
- iconIndex dd ?
- iconFlags dd ?
- hiconLarge dd ?
- hiconSmall dd ?
- uname1 du 'c:\windows\notepad.exe',0
- uname2 du 'c:\windows\explorer.exe',0
- ...
- ; Получить объект рабочего стола
- invoke SHGetDesktopFolder,psfDesktop
- ; Получить объект файла
- mov eax,[psfDesktop]
- mov eax,[eax]
- stdcall dword [eax+IShellFolder2.ParseDisplayName],[psfDesktop],\
- NULL,NULL,uname1,NULL,pidl,NULL
- ; Клонировать последнюю запись структуры ITEMIDLIST
- invoke ILFindLastID,[pidl]
- invoke ILClone,eax
- mov [pidlRelative],eax
- ; Удалить последнюю запись структуры ITEMIDLIST
- invoke ILRemoveLastID,[pidl]
- ; Получить интерфейс IShellFolder2
- mov eax,[psfDesktop]
- mov eax,[eax]
- stdcall dword [eax+IShellFolder2.BindToObject],[psfDesktop],\
- [pidl],NULL,IID_IShellFolder2,appObject
- ; Очистить структуру ITEMIDLIST
- invoke ILFree,[pidl]
- ; Получить интерфейс IExtractIcon
- mov eax,[appObject]
- mov eax,[eax]
- stdcall dword [eax+IShellFolder2.GetUIObjectOf],[appObject],\
- NULL,1,pidlRelative,IID_IExtractIconW,NULL,extractIcon
- ; Очистить структуру ITEMIDLIST
- invoke ILFree,[pidlRelative]
- ; Получить хранилище и индекс иконки
- mov eax,[extractIcon]
- mov eax,[eax]
- stdcall dword [eax+IExtractIcon.GetIconLocation],[extractIcon],\
- NULL,iconLocation,MAX_PATH,iconIndex,iconFlags
- ; Извлечь иконку 64х64
- mov eax,[extractIcon]
- mov eax,[eax]
- stdcall dword [eax+IExtractIcon.Extract],[extractIcon],\
- iconLocation,[iconIndex],hiconLarge,hiconSmall,(16 shl 16 + 64)
- ; [hiconLarge] - хэндл большой иконки
- ; [hiconSmall] - хэндл маленькой иконки
- ; Извлечь иконку 16х16
- mov eax,[extractIcon]
- mov eax,[eax]
- stdcall dword [eax+IExtractIcon.Extract],[extractIcon],\
- iconLocation,[iconIndex],hiconLarge,hiconSmall,(16 shl 16 + 16)
- ; [hiconLarge] - хэндл большой иконки
- ; [hiconSmall] - хэндл маленькой иконки
- ; Извлечь иконку и отмасштабировать ее в 6х6
- mov eax,[extractIcon]
- mov eax,[eax]
- stdcall dword [eax+IExtractIcon.Extract],[extractIcon],\
- iconLocation,[iconIndex],hiconLarge,hiconSmall,(16 shl 16 + 6)
- ; [hiconLarge] - хэндл большой иконки
- ; [hiconSmall] - хэндл маленькой иконки
- ; Извлечь иконку 48х48 по прямому пути и индексу
- mov eax,[extractIcon]
- mov eax,[eax]
- stdcall dword [eax+IExtractIcon.Extract],[extractIcon],\
- uname2,1,hiconLarge,hiconSmall,(16 shl 16 + 48)
- ; [hiconLarge] - хэндл большой иконки
- ; [hiconSmall] - хэндл маленькой иконки
Code (Assembler) : Убрать нумерацию
- ...
- fname db 'source.exe',0
- fext db '*.jpg',0
- iconIdx dd ?
- xfile rb MAX_PATH
- ...
- invoke GetModuleHandle,NULL
- mov ebx,eax
- ; Извлечь первую и вторую иконки из исполняемого файла
- mov [iconIdx],0
- invoke lstrcpy,xfile,fname
- invoke ExtractAssociatedIcon,ebx,xfile,iconIdx
- ; EAX - хэндл первой большой иконки
- mov [iconIdx],1
- invoke lstrcpy,xfile,fname
- invoke ExtractAssociatedIcon,ebx,xfile,iconIdx
- ; EAX - хэндл второй большой иконки
- ; Попытаться извлечь иконку из несуществующего файла
- mov [iconIdx],0
- invoke lstrcpy,xfile,fext
- invoke ExtractAssociatedIcon,ebx,xfile,iconIdx
- ; Строка xfile перезаписана
Code (Assembler) : Убрать нумерацию
- SHGFI_USEFILEATTRIBUTES = 0x000000010
Code (Assembler) : Убрать нумерацию
- ...
- fname db 'c:\Documents\export.xls',0
- fext db '*.jpg',0
- FileInfo SHFILEINFO
- ...
- ; Имя файла, не обязательно существующего
- invoke SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_LARGEICON+SHGFI_USEFILEATTRIBUTES
- ; [FileInfo.hIcon] - хэндл большой иконки, связанной с файлом
- invoke SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_SMALLICON+SHGFI_USEFILEATTRIBUTES
- ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с файлом
- ; Расширение без указания конкретного файла
- invoke SHGetFileInfo,fext,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_LARGEICON+SHGFI_USEFILEATTRIBUTES
- ; [FileInfo.hIcon] - хэндл большой иконки, связанной с расширением
- invoke SHGetFileInfo,fext,0,FileInfo,sizeof.SHFILEINFO,\
- SHGFI_ICON+SHGFI_SMALLICON+SHGFI_USEFILEATTRIBUTES
- ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с расширением
Еще может пригодиться функция PathParseIconLocation, которая парсит текстовую строку вида "path\filename.exe,3" и возвращает имя файла и индекс иконки, которую надо из него извлечь. Такой формат записи характерен для всяких конфигурационных файлов. Но пользоваться этой функцией надо с большой осторожностью, так как исходная строка модифицируется. Зато при правильном использовании отпадает необходимость в изобретении велосипедов, всю грязную работу сделает система.
Ну и совсем напоследок код, который сбрасывает кеш иконок в Проводнике. Это бывает полезно, например, когда надо обновить данные после изменения ассоциаций.
Code (Assembler) : Убрать нумерацию
- invoke SHChangeNotify,SHCNE_ASSOCCHANGED,SHCNF_IDLIST,NULL,NULL
Просмотров: 2397 | Комментариев: 2

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(10.11.2020 в 15:56):
Добавил пример работы с иконками через COM, архив обновлен.

ManHunter
(09.11.2020 в 16:48):
Добавил пример работы с LoadIconWithScaleDown. Архив обновлен.

Добавить комментарий
Заполните форму для добавления комментария
