Автор: Джон.
"Товарищи! Я, конечно, не лектор. Укротитель я." (c)
воспоминания, посвящается. ;-)
Конечно, неплохо было бы размусолить кучу примеров когда это нужно, а когда нет, но при наличии отсутствия, как любил говаривать один литературный герой, кучи свободного времени буду краток. Предлагаемый способ не претендует на окончательное и 100% решение данной проблемы и, если не даёт 100% автоматизацию, то во всяком случае позволяет сильно облегчить ручной труд.
Есть большой проект Visual C++ .NET 2003 с кучей ресурсов (rc-файл 300 КБ, ~7200 строчек, компилированная версия ресурсов весит почти 4 МБ, exe - 10M), который ведётся на протяжении нескольких лет. В разработке участвовала целая куча программеров, из которых "иных уж нет, а те далече".
Задание.
На основе существующего кода и ресурсов создать облегчённую версию с ограниченными функциями: выкинуть пару дюжин диалогов, битмапов, как основных пожирателей места, кнопок, меню и тд; добавить пару диалогов и меню.
При этом проект (код) должен оставаться в единственном, насколько это возможно, уникальном экземпляре. Причём разработка продолжается и все изменения, затрагивающие общие объекты, должны находить отображение в обоих версиях. "Фи, да как нефиг делать", - воскликнут додиезники. Но тут им обломается - на выходе должен быть единственный ЕХЕ-файл. К сожалению, разбить на модули (даже если бы это было возможно практически!) нельзя. Да и гибкости такой у сиплюплюснутых всё равно нет.
Ну, с кодом вроде всё понятно: расставил где надо #ifdef да #ifndef, и готово. А вот как с ресурсами быть?
Переходим к пошаговой инструкции (мне так проще излагать, а вам, наверное, читать) на примере небольшого проекта. В нём мы создадим базу для раздельных ресурсов и удалим несколько кнопок из ToolBar.
1. Создаём проект (или используем готовый), типа MDI - для пущей сложности, называем его TestPrj.
2. Добавляем необходимые конфигурации. Обычно стандартный мастер создаёт две конфигурации Debug и Release. Создадим новые Debug LT и Release LT на их основе.
- Меню -> Build -> Configuration Manager.
- Из списка Active Solution Configuration: выбираем <New...>
- В поле Solution Configuration Name: впечатываем Debug LT
- В списке Copy Settings from выбираем Debug
- Подтверждаем Ок
- Повторяем действия и создаём конфигурацию Release LT на основе Release
3. Теперь изменим эти две новые конфигурации.
Внимание! Перечисленные ниже действия необходимо проделать последовательно для обеих конфигураций: Debug LT и Release LT.
- Меню -> Project -> Properties
- В С/С++ -> Preprocessor -> Preprocessor Definitions добавляем LT_VERSION
- Изменим имя выходного файла для LT конфигурации
- Linker -> General -> Output File: изменим $(OutDir)/$(ProjectName).exe на $(OutDir)/$(ProjectName)_LT.exe
Добавим ключик для ресурсов
- В Resources -> General -> Preprocessor Definitions добавляем LT_VERSION
И поменяем имя файла для компилированных ресурсов
- Resources -> General -> Resource File Name изменим $(IntDir)/$(InputName).res на $(IntDir)/$(InputName)_LT.res
Собственно, ничего нового и служит только логическим началом. Теперь начинаем разделять ресурсы.
4. Идём в папку проекта и делаем копии файлов.
- TestPrj.rc -> TestPrj_LT.rc
- Resource.h -> Resource_LT.h
5. Редактируем файлы в любом доступном текстовом редакторе.
В Resource_LT.h в блоке
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by TestPrj.rc
//
Меняем TestPrj.rc на TestPrj_LT.rc .
Вот так он должен выглядеть.
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by TestPrj_LT.rc
//
Сохраняем файл. Несмотря на то, что эта строчка закомментирована, она читается парсером редактора ресурсов, посредством этой строчки обеспечивается обратная связь: .h -> .rc .
Изменения в TestPrj_LT.rc. Ищем в тексте включения resource.h и меняем их на resource_LT.h. Обычно таких включений два:
#include "resource.h"
#include "resource_LT.h"
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
1 TEXTINCLUDE
BEGIN
"resource_LT.h\0"
END
Сохраняем файл.
6. Добавим новые файлы в проект.
7. В Solution Explorer кликаем правой кнопкой на TestPrj_LT.rc и в контекстном меню выбираем Properties.
- В списке Configuration: выбираем Multiple Configurations.
- Выделяем в списке всё, кроме LT-конфигураций (в реальном проекте их может быть больше), в нашем случае Debug и Release -> OK
- General -> Excluded From Build -> Yes
Таким образом, мы исключили LT-ресурсы из "НЕ"-LT-компиляций.
8. Аналогично исключаем TestPrj.rc из LT-компиляций. Для этого в Multiple Configurations выделяем LT-конфигурации.
Внимание! Обычно при добавлении файлов в проект Excluded From Build у них установлен в No. По косвенным сведениям, это не всегда так. Поэтому проверьте эту опцию для нужных конфигураций.
В принципе всё. Разделение ресурсов закончено. Нормальная сборка и сборка LT дадут два одинаковых файла.
Теперь их можно раздельно редактировать. Добавим последний штрих.
9. Проблема заключается в том, что ToolBar используют картинки прозрачно для пользователя. Редактор ресурсов динамически создаёт и изменяет готовый битмап. Это же относится и к другим ресурсам, использующим "внешние" файлы (bmp, ico, cur). Если предусматриваются изменения этих ресурсов в различных конфигурациях, то их тоже нужно клонировать.
На данном этапе у нас есть два ресурса, которые работают с одним и тем же битмапом. Оба ToolBar, и в нормальной версии, и в LT работают с Toolbar.bmp. Сделаем копию этого файла и назовём её Toolbar_LT.bmp. Добавим её в проект.
Теперь идём в редактор ресурсов Resource View и в LT-ресурсах (TestPrj_LT.rc) -> ToolBar переопределяем файл для IDR_MAINFRAME:
- Filename: res\Toolbar.bmp -> res\Toolbar_LT.bmp
Всё. Теперь их можно изменять абсолютно независимо друг от друга. Удалим несколько кнопок и откомпилируем проект. Выбирая ту или иную компиляцию, получим разные ресурсы.
На уровне кода используются проверки #ifndef LT_VERSION или #ifdef LT_VERSION. Если надо исключить полностью .cpp файлы - лучше воспользоваться опцией Excluded From Build, как мы это проделали с rc-файлами. Её можно устанавливать сразу у нескольких выделенных файлов.
Редактирование текстовых ресурсов, меню и диалогов не требует никаких дополнительных действий. Если что-то случайно удалили - всегда можно скопировать этот ресурс из другой компиляции. Копирование можно использовать и при добавлении общих ресурсов. Например, можно полностью добавить диалог, или только его часть. Вроде, всё... Ничего не забыл?
Copyright 2008. Все права принадлежат Клубу программистов "Весельчак У"