Манифест приложения на ассемблере

Метки:  , ,

Когда я, в процессе своего обучения, подошел к написанию приложений, активно использующих различные графические элементы управления, раз за разом начал обращать внимание на одну интересную проблему. Дело в том, что при запуске двоичного исполняемого файла, все элементы, находящиеся в окне, выглядели "плоско", то есть имели упрощенный стиль, а-ля Windows 95/98. Долгое время я как-то не мог сообразить, почему у меня из раза в раз оформление окон получается каким-то упрощенным, без выпуклого объема кнопок, теней, объемных полос прокруток, элегантных тонких линий-рамок у групп элементов, а у подавляющего большинства сторонних оконных приложений, видимых мною в Сети, тема оформления окна как раз была "объемной"? Особенно это заметно в диалоговых окнах, где группируется большое количество разнообразных дочерних элементов управления, волей-неволей начинаешь к ним присматриваться, изучать детали.. и тут вот осознаешь, что в твоих то приложениях они получаются не такими элегантными. Оказалось, что если не предпринимать каких-либо дополнительных действий, то приложения, компилируемые FASM и использующие оконный графический интерфейс, все как на подбор получаются с упрощенной стилизацией интерфейса. Что я только не делал, уже и все стили элементов перебрал вдоль и поперек, ставя в параметры ресурсов всяческие мыслимые и немыслимые комбинации, эффект был разный, но неизменно далекий от желаемого. Как заставить приложение выглядеть в новом, современном стиле? В ходе практических изысканий, когда уже все варианты кончились, наконец-то начал думать :) Как оказалось, ответ кроется в изменившихся принципах работы с общими элементами управления, подключаемых посредством механизма под названием манифест приложения.

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

Поскольку темой серии статей является изучение программирования под Windows на языке ассемблера, то и рассматривать мы будем тут преимущественно особенности подключения манифеста приложения применительно к приложению на ассемблере. Для начала обратимся к официальным источникам, согласно определению манифеста с сайта Microsoft:

Манифест — это документ формата XML (внешний XML-файл или же внутренний ресурс), определяющий имена общих и приватных сборок (в том числе и библиотек), с которыми приложение должно быть "связано" на этапе загрузки/выполнения. Фактически, манифест приложения задает его зависимости от имен, версий, ресурсов и прочего.

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

Использование тем оформления

Начиная с Windows XP, команда визуального оформления Windows решила изменить комплексный подход к оформлению интерфейса приложений, при этом сохранив совместимость со старыми функциональными особенностями. Результатом этого явилось создание новых системных библиотек, которые содержали иначе стилизованные версии ключевых элементов управления. При этом, в системе оставили старые версии user32.dll и comctl32.dll, добавив следующую версию comctl32.dll и принципиально новую библиотеку uxctrl.dll.

Чтобы указать приложению использовать темы оформления, необходимо использовать comctl32.dll версии 6 или более поздней. Осуществляется подключение библиотеки Common Controls при помощи задания в манифесте имени атрибута Microsoft.Windows.Common-Controls с непосредственным указанием версии 6.0.0.0, тем самым инициируя связывание процесса приложения (на стадии подготовки/выполнения) с библиотекой comctl32.dll шестой версии. Вследствие подобного связывания, все стандартные контролы рисуются в соответствии с активированной в системе темой оформления. Эта особенность впервые появилась в Windows XP и до сих пор актуальна для более поздних её версий.

Если же вы не настраиваете элементы манифеста подобным образом, или манифест и вовсе не используется в вашем приложении, то система (по умолчанию) грузит comctl32.dll пятой (старой) версии, которая отрисовывает элементы управления в традиционном ретро-стиле Windows 95/98.

Алгоритм настройки манифеста приложения

Давайте непосредственно от теории перейдем к практике и попытаемся сконфигурировать манифест приложения на ассемблере.

Приведенная ниже последовательность действий применима к приложению, написанному на ассемблере FASM.

Загрузка общих элементов управления

В самом начале листинга программы, до вызова функции GetModuleHandle, добавляем строку:

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

Добавление записей в секцию импорта

Для того, что бы вызов функции InitCommonControlsEx был возможен, необходимо подключить библиотеку общих элементов управления. Для этого:

  • в секцию .idata, к макроопределению library в конце добавить строку: ,comctl32,'COMCTL32.DLL';
  • в ту же секцию .idata, в конце, добавляем подключаемые определения строкой: include 'api\comctl32.inc';

Полная получившаяся в итоге секция импорта может выглядеть, например, таким вот образом:

Добавление записей в секцию ресурсов

  1. В ресурсной секции .rsrc, в макроопределении directory, описываем новую директорию manifests с идентификатором RT_MANIFEST (24). Получившаяся строка может выглядеть следующим образом:

    Константа RT_MANIFEST, как мы видим, не требует непосредственного определения в приложении, поскольку она уже инициализирована в подключаемых файлах kernel32.inc и kenel64.inc.
  2. Затем, в этой же секции .rsrc конфигурируем ресурсную запись с именем manifests и идентификатором 1:

Добавление манифеста

Если Вы хотите разместить данные манифеста непосредственно в исходном коде (что несомненно удобно), то в самый конец секции ресурсов (обычно в конце исходного кода) добавляем:

В строке 4 задается атрибут name дочернего элемента assemblyIdentity, в нем можно указать имя приложения в произвольном формате (с пробелом и без). В строке 5 у нас располагается элемент description, в котором можно задавать описание, зачастую совпадающее с именем.

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

.. в этом случае особое внимание следует обратить на факт присутствия файла manifest.xml в директории проекта с таким вот содержимым:

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

<имя_программы>.exe.manifest

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

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