Blog. Just Blog

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

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Работа с иконками файлов на Ассемблере
Работа с иконками файлов на Ассемблере

Я уже рассказывал, как можно получить иконку из окна чужого приложения, сегодня тема будет похожей. Разница в том, что иконку мы будем получать из файла на диске. Применений для этого может быть много, например, чтобы отрисовать в вашем приложении красивый список файлов, нарисовать всплывающее меню, заменить иконку в собранном джойнере или патче. Для работы с иконками в WInAPI есть несколько функций, каждая со своими особенностями. В этой статье я попытаюсь подробно рассказать о них.

Первая функция - ExtractIcon, она по индексу извлекает иконку из исполняемого файла, динамической библиотеки или файла иконки. С ее же помощью можно узнать количество иконок в файле. Главный недостаток использования ExtractIcon заключается в том, что извлекаются только большие иконки 32х32, если значок, находящийся по запрошенному индексу, имеет другой размер, то он будет отмасштабирован.
  1. ...
  2. fname  db 'source.exe',0
  3. ...
  4.         invoke  GetModuleHandle,NULL
  5.         mov     ebx,eax
  6.         invoke  ExtractIcon,ebx,fname,0
  7.         ; EAX - хэндл первой иконки
  8.         invoke  ExtractIcon,ebx,fname,1
  9.         ; EAX - хэндл второй иконки
ExtractIconEx - как можно понять из названия, представляет собой расширенный вариант предыдущей функции. Кроме того, что с ее помощью также можно получить количество иконок в файле, она позволяет извлекать как большие 32х32, так и маленькие 16х16 иконки, причем сразу пачками. Источником может быть исполняемый файл, динамическая библиотека или файл иконки.
  1. ...
  2. fname  db 'source.exe',0
  3.  
  4. hIconLarge dd ?
  5. hIconSmall dd ?
  6.  
  7. arrSmall   rd 4
  8. ...
  9.         ; Извлечь по одной большой и маленькой иконке с индексом 0
  10.         invoke  ExtractIconEx,fname,0,hIconLarge,hIconSmall,1
  11.         ; [hIconLarge] - хэндл большой иконки
  12.         ; [hIconSmall] - хэндл маленькой иконки
  13.  
  14.         ; Извлечь из файла только маленькие иконки в количестве 4 штук,
  15.         ; начиная с индекса 0 и до 3
  16.         invoke  ExtractIconEx,fname,0,NULL,arrSmall,4
  17.         ; [arrSmall] - массив с четырьмя хэндлами маленьких иконок
Здесь следует сделать небольшое отступление. Дело в том, что в системе используются термины "большие иконки" и "маленькие иконки". Исторически сложилось, что размер больших иконок составляет 32х32 пиксела, а маленьких 16х16 пикселов. Однако, эти значения не являются непоколебимыми константами. Если вы пишете максимально устойчивое и адаптивное приложение, вам надо обязательно проверять размеры иконок, заданные в системе. Делается это при помощи функции GetSystemMetrics с флагами SM_CXICON, SM_CYICON для больших и SM_CXSMICON, SM_CYSMICON для маленьких иконок. Конечно, в абсолютном большинстве случаев полученные размеры иконок не будут отличаться от привычных 16 и 32, но мало ли. Для простоты понимания в статье и исходниках я буду подразумевать, что размеры больших и маленьких иконок стандартные.
  1.         ; Получить системные размеры больших и маленьких иконок
  2.         invoke  GetSystemMetrics,SM_CXICON
  3.         ; EAX = ширина большой иконки
  4.         invoke  GetSystemMetrics,SM_CYICON
  5.         ; EAX = высота большой иконки
  6.         invoke  GetSystemMetrics,SM_CXSMICON
  7.         ; EAX = ширина маленькой иконки
  8.         invoke  GetSystemMetrics,SM_CYSMICON
  9.         ; EAX = высота маленькой иконки
А как быть, если в файле хранятся иконки с другими размерами, например, 64х64 или вовсе 256х256? Как их извлечь, не забираясь в дебри ресурсов? Делается это при помощи следующей функции - PrivateExtractIcons. Если почитать ее описание на MSDN, то там английским по белому написано, что эта функция не рекомендована к использованию и может быть в любой момент изменена или вовсе исключена из очередной версии Windows. Как бы то ни было, PrivateExtractIcons исправно работает аж со времен Windows 2000 и до настоящего времени никаких проблем с ее использованием нет. Более того, это единственная функция, позволяющая наиболее быстро и просто извлекать из файла иконки нужных размеров, отличных от "больших" и "маленьких". Если по запрошенному индексу нет иконки подходящего размера, то будет загружена наиболее подходящая по размеру и отмасштабирована под заданные пропорции. Поддерживается и пакетное извлечение иконок, но только из исполняемых файлов и динамических библиотек. Одиночные изображения с помощью функции PrivateExtractIcons можно загружать из файлов иконок, анимированных курсоров и даже BMP-файлов. Поэтому функцию можно использовать для быстрой загрузки изображений с автоматическим изменением размера.
  1. ...
  2. fname  db 'source.exe',0
  3.  
  4. hIcon dd ?
  5. tmp   dd ?
  6. ...
  7.         ; Загрузить иконки разных размеров
  8.         invoke  PrivateExtractIcons,fname,0,24,24,hIcon,tmp,1,LR_LOADTRANSPARENT
  9.         ; [hIcon] - хэндл загруженной иконки
  10.         invoke  PrivateExtractIcons,fname,2,64,64,hIcon,tmp,1,LR_LOADTRANSPARENT
  11.         invoke  PrivateExtractIcons,fname,3,256,256,hIcon,tmp,1,LR_LOADTRANSPARENT
  12.         ; Иконка несуществующего размера 22х60
  13.         invoke  PrivateExtractIcons,fname,1,22,60,hIcon,tmp,1,LR_LOADTRANSPARENT
  14.         ; [hIcon] - хэндл загруженной иконки
Последний способ получения иконок из файлов - использование функции SHGetFileInfo. С ее помощью можно узнать много интересного о любом файле, в том числе получить хэндлы большой или маленькой иконки, связанной с ним. Говоря "связанной", подразумевается, что для исполняемых файлов, динамических библиотек и файлов иконок будет извлечена их собственная иконка, а для прочих файлов - иконка приложения, ассоциированного с ними. Кроме того, SHGetFileInfo может получать иконки не только файлов, но и папок. Для FASM "из коробки" эта функция неизвестна, поэтому придется сперва объявить структуру и константы, необходимые для работы.
  1. struct SHFILEINFO
  2.   hIcon dd ?
  3.   iIcon dd ?
  4.   dwAttributes dd ?
  5.   szDisplayName rb MAX_PATH
  6.   szTypeName rb 80
  7. ends
  8.  
  9. SHGFI_ICON      = 0x000000100
  10. SHGFI_SMALLICON = 0x000000001
  11. SHGFI_LARGEICON = 0x000000000
Использование же SHGetFileInfo очень простое:
  1. ...
  2. fname  db 'source.exe',0
  3. fdir   db 'c:\windows',0
  4.  
  5. FileInfo SHFILEINFO
  6. ...
  7.         invoke  SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
  8.                 SHGFI_ICON+SHGFI_LARGEICON
  9.         ; [FileInfo.hIcon] - хэндл большой иконки, связанной с файлом
  10.  
  11.         invoke  SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
  12.                 SHGFI_ICON+SHGFI_SMALLICON
  13.         ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с файлом
  14.  
  15.         ; Папка
  16.         invoke  SHGetFileInfo,fdir,0,FileInfo,sizeof.SHFILEINFO,\
  17.                 SHGFI_ICON+SHGFI_LARGEICON
  18.         ; [FileInfo.hIcon] - хэндл большой иконки, связанной с папкой
  19.  
  20.         invoke  SHGetFileInfo,fdir,0,FileInfo,sizeof.SHFILEINFO,\
  21.                 SHGFI_ICON+SHGFI_SMALLICON
  22.         ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с папкой
Раз уж мы затронули тему иконок, ассоциированных с файлами разных типов, логично было бы рассмотреть функции, которые используются для их получения. На различных форумах чаще всего рекомендуют пользоваться стандартной функцией ExtractAssociatedIcon. Казалось бы, очень удобная функция: передал указатель на имя проверяемого файла, получил хэндл иконки с нужным индексом. Для и для исполняемых файлов тоже годится. На самом деле все получается не так красиво. Функция ExtractAssociatedIcon возвращает хэндл только большой иконки, то есть 32х32, иконки других размеров будут отмасштабированы. А самые приколы начинаются, если попытаться вызвать функцию для несуществующего файла. В этом случае буфер с переданным именем файла перезапишется чем-то вроде "C:\Windows\system32\shell32.dll" и никакого хэндла иконки не вернется. Если имя файла хранится в защищенном от записи участке памяти или под него зарезервирована более короткая строка, то результат может получиться непредсказуемым. Отловить такую ошибку будет непросто. А главный недостаток в том, что через ExtractAssociatedIcon нельзя просто взять и получить иконку, связанную с каким-либо расширением, без указания реально существующего файла с таким расширением.
  1. ...
  2. fname   db 'source.exe',0
  3. fext    db '*.jpg',0
  4. iconIdx dd ?
  5. xfile   rb MAX_PATH
  6. ...
  7.         invoke  GetModuleHandle,NULL
  8.         mov     ebx,eax
  9.  
  10.         ; Извлечь первую и вторую иконки из исполняемого файла
  11.         mov     [iconIdx],0
  12.         invoke  lstrcpy,xfile,fname
  13.         invoke  ExtractAssociatedIcon,ebx,xfile,iconIdx
  14.         ; EAX - хэндл первой большой иконки
  15.         mov     [iconIdx],1
  16.         invoke  lstrcpy,xfile,fname
  17.         invoke  ExtractAssociatedIcon,ebx,xfile,iconIdx
  18.         ; EAX - хэндл второй большой иконки
  19.  
  20.         ; Попытаться извлечь иконку из несуществующего файла
  21.         mov     [iconIdx],0
  22.         invoke  lstrcpy,xfile,fext
  23.         invoke  ExtractAssociatedIcon,ebx,xfile,iconIdx
  24.         ; Строка xfile перезаписана
Всех перечисленных недостатков функции ExtractAssociatedIcon лишена уже знакомая нам функция SHGetFileInfo. При извлечении ассоциированных иконок всего лишь потребуется указать один дополнительный флаг, в остальном все остается прежним.
  1. SHGFI_USEFILEATTRIBUTES = 0x000000010
  1. ...
  2. fname   db 'c:\Documents\export.xls',0
  3. fext    db '*.jpg',0
  4.  
  5. FileInfo SHFILEINFO
  6. ...
  7.         ; Имя файла, не обязательно существующего
  8.         invoke  SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
  9.                 SHGFI_ICON+SHGFI_LARGEICON+SHGFI_USEFILEATTRIBUTES
  10.         ; [FileInfo.hIcon] - хэндл большой иконки, связанной с файлом
  11.         invoke  SHGetFileInfo,fname,0,FileInfo,sizeof.SHFILEINFO,\
  12.                 SHGFI_ICON+SHGFI_SMALLICON+SHGFI_USEFILEATTRIBUTES
  13.         ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с файлом
  14.  
  15.         ; Расширение без указания конкретного файла
  16.         invoke  SHGetFileInfo,fext,0,FileInfo,sizeof.SHFILEINFO,\
  17.                 SHGFI_ICON+SHGFI_LARGEICON+SHGFI_USEFILEATTRIBUTES
  18.         ; [FileInfo.hIcon] - хэндл большой иконки, связанной с расширением
  19.         invoke  SHGetFileInfo,fext,0,FileInfo,sizeof.SHFILEINFO,\
  20.                 SHGFI_ICON+SHGFI_SMALLICON+SHGFI_USEFILEATTRIBUTES
  21.         ; [FileInfo.hIcon] - хэндл маленькой иконки, связанной с расширением
Я встречал еще один способ получения иконок, ассоциированных с расширениями файлов. Но там данные о приложениях, связанных с расширением, читались из реестра, затем из найденных приложений извлекались иконки одним из вышеперечисленных способов. Из-за абсолютной неэффективности и монстрячности этого способа я его даже не буду рассматривать.

В приложении пример программы с исходным текстом, которая извлекает иконки из файлов всеми перечисленными способами. Результат сразу же показывается в диалоговом окне.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Read.Icons.Demo.zip (38,086 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 584 | Комментариев: 0

Метки: Assembler, иконки

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2018
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0042 сек.) / Память: 4.75 Mb
Наверх