Иконка приложения на ассемблере

Метки:  , , , ,

Затрагиваемая нами сегодня тема, пожалуй, является не такой уж и заметной в общем процессе освоения программирования на языке ассемблера под Windows. Однако возможность обеспечения разрабатываемого приложения различного рода визуальными элементами, если хотите украшательствами, заложена в саму концепцию большинства современных операционных систем с графическим интерфейсом. Сегодня мы обсудим такую несущественную деталь как иконка приложения. Согласитесь, в сущности то мелочь, а придает, так сказать, некий дополнительный уровень основательности в восприятии приложения. В очередной раз как-то на днях увидел элегантную иконку напротив имени какой-то программы в проводнике, и.. понравилось. Эстетика, не более, никакого особенного функционала в себе иконки не несут, однако восприятие графического окна приложения как то сразу меняется. Ведь, если разобраться, в современном программировании наличие собственного значка у приложения является уже своего рода хорошим тоном, так сказать распространенной практикой. Ну, а поскольку для меня программирование под Windows является областью пока еще новой, поэтому решил разобраться, как же собственные приложения, написанные на ассемблере, оснащать иконками. Иконка приложения, о которой идет речь, видна в верхнем левом углу главного окна программы, отображается в проводнике напротив имени файла и её так же можно наблюдать в миниокне приложения на панели задач, по сути, она доступна через стандартные системные механизмы, поэтому появляется везде, где её запрашивают и выводят.

За основу мы возьмем исходный код шаблона приложения на ассемблере, который, в свою очередь, взят из комплекта стандартного дистрибутива FASM. Затем внесем в него изменения, касающиеся иконки, которые я отметил в исходном файле цветом:

Как мы видим, изменений исходного шаблона немного и связаны они с модификацией кода загрузки иконки (строка 14) и добавлением секции ресурсов (строки: 90-104), описывающей данные пиктограммы выходного исполняемого файла.
Начнем изучение изменений с самого начала листинга. У нас еще с первого примера в исходном коде присутствует функция загрузки иконки LoadIcon, которую можно увидеть в строке 14. В начальном шаблоне функция LoadIcon использовалась для загрузки стандартной системной иконки. Однако, в случае с пользовательской пиктограммой (иконкой) стоит более внимательно изучить документацию по функции, дабы понять, что нам необходимо скорректировать входные параметры. В частности, параметр hInstance должен принять значение дескриптора модуля, чей исполняемый файл содержит в своей ресурсной секции битовую карту иконки. Очевидно, что это значение у нас поступает в виде выходного параметра функции GetModuleHandle (строка 12) и на момент вызова LoadIcon содержится в переменной wc.hInstance (или в регистре eax). Затем, второй входной параметр lpIconName функции LoadIcon должен принимать значение идентификатора загружаемого ресурса (иконки), вот тут то и начинается самое интересное. Что такое значение 2 идентификатора ресурса и ресурс вообще? Это термины отсылают нас к понятию секции ресурсов.

Секция ресурсов

Думаю будет более чем уместным упомянуть о секции ресурсов, поскольку описание ресурсов пиктограммы является краеугольным камнем понимания всей стратегии задания иконки приложения. Настоятельно рекомендую немного отвлечься и изучить информацию по секции ресурсов, которую я собрал в отдельной статье. Тут можно лишь отметить, что ресурсы - индексированный массив статических (неизменяемых) данных, используемых в коде приложения или иным образом относящихся к нему: меню, диалоги, курсоры, иконки, картинки, звуки и прочее. Для описания ресурсов, как вы уже поняли, используется специальная секция, которая начинается с директивы section, и определяемых после неё различных опции, таких как название (.rsrc), тип (resource data), атрибуты доступа (readable).

В FASM для описания ресурсов используются специализированные макроопределения, за счет чего ресурсы описываются несколько иначе, чем в других компиляторах.

Поэтому, в статье, которую я порекомендовал выше, достаточно подробно описаны основные ключевые макросы, используемые в FASM для секции ресурсов. Тут мы поясним только лишь некоторые моменты:

Наименование Определение
Макроопределение icon Данные (ресурс) иконки. Макрос icon завершает секцию ресурсов в строке 103, он призван организовать размещение иконки приложения в секции ресурсов. В параметрах макроса указаны: имя ресурса группы иконок (main_icon), имя ресурса отдельной иконки (icon_data), имя файла с иконкой (icon.ico). Понятное дело, что при запуске исполняемого файла нам сам файл иконки уже будет не нужен, однако на стадии сборки исполняемого файла компилятор должен откуда то получить данные, дабы сформировать соответствующую поддиректорию секции ресурсов.

В нашем примере подразумевается, что файл icon.ico размещается в той же директории, что и исходный код программы, однако нет никаких проблем с выбором произвольного местоположения внешних данных для секции ресурсов, поэтому, если у Вас вдруг возникло желание положить иконки в отдельную поддиректорию, то необходимо будет соответствующим образом подкорректировать параметр.
Но, вернемся к нашему примеру. В итоге всех наших манипуляций, подключенную нами иконку можно разглядеть в левом верхнем углу основного окна приложения:

application icon

В дополнение к этому, иконка приложения появляется и в пиктограмме на панели задач. Ну и ко всему прочему такой вот вид теперь принимает исполняемый файл нашей программы в проводнике:

app explorer icon

видите слева от имени программы появилась иконка? Похоже код проводника тоже опрашивает ресурсные секции файлов каталога, кеширует их и затем отображает в открывшемся окне проводника.

Формат и размерность иконки

Тут возникает резонный вопрос, а почему в качестве формата иконок выбран .ico? Честно говоря, за время, проведенное в работе с операционными системами Windows, у меня сложилась устойчивая ассоциация, что стандартом де-факто для иконок (пиктограмм) в этой системе непременно должен являться указанный формат. И действительно, об этом же красноречиво говорит и Wikipedia:

ICO (Windows icon) — формат хранения файлов значков в Microsoft Windows.

Однако, развитие видов представления в различных компонентах ОС способствовало увеличению необходимых разрешений иконок. Теоретически, размер иконки приложения может быть любым, однако разработчиками из Microsoft рекомендованы следующие размеры: 16×16, 24×24, 32×32, 48×48, 256×256. В нашем же примере я особо не мудрствовал и нашел в Сети первый попавшийся .ico-файл размером 16х16, который и был использован в коде.

Описанный в статье метод подключения иконки приложения позволяет сконфигурировать одиночную иконку.

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

Размер файла иконки

Потом я заметил, что моя иконка занимает на диске 2.5 Кб, а сам скомпилированный исполняемый файл тестовой программы - всего-лишь 2 Кб. Вот это да, оказывается что иконка приложения у меня "весит" больше нежели сама программа! Реалии современного программирования под Windows таковы, что размеры давно никого уже не стесняют, ведь если какой-нибудь инсталлятор современного пакета занимает несколько сотен мегабайт, то какое кому дело до размера иконки? Но я лично привык к рациональному использованию ресурсов системы, поэтому у меня возникло острое желание оптимизировать иконку по размеру.
В этом случае можно попробовать:

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *