Ресурсы VC ++ в статической библиотеке

Можно ли создавать ресурсы в статической библиотеке и повторно использовать их, просто связывая с библиотекой?

Я в первую очередь думаю о случае, когда вы вызываете функцию в библиотеке, которая, в свою очередь, обращается к ресурсам.

Это можно сделать, но это довольно болезненно: вы не можете сделать это, просто связавшись со статической библиотекой.

Рассмотрим это: ресурсы встроены в EXE или DLL. Когда какой-то код в статической библиотеке вызывает (например, LoadIcon), он получит ресурсы из EXE или DLL, с которыми он связан.

Итак, если ваша статическая библиотека требует наличия ресурсов, у вас есть несколько вариантов:

  1. Вы можете создать библиотеку на лету, а затем использовать (например) CreateDialogIndirect . См. «Создание диалогового шаблона во время выполнения» Раймонда Чена.
  2. Вы можете встроить их в библиотеку как простые массивы (т. char my_dialog_resource[] = { .... }; , а затем используйте (например) CreateDialogIndirect . Вам, вероятно, придется найти (или написать) утилиту, которая преобразует файлы .CPP файлы .CPP .
  3. Вы можете отправить файл LIB с помощью сценария ресурса (файл .RC ) и соответствующего файла заголовка. Затем вы #include их как соответствующие. Вам необходимо зарезервировать ряд идентификаторов ресурсов для использования LIB, чтобы они не сталкивались с целями основного EXE или DLL. Это то, что MFC делает, когда используется как статическая библиотека. Или вы можете использовать идентификаторы строковых ресурсов (это не работает для ресурсов STRINGTABLE ).
  4. Ваша статическая библиотека может поставляться с отдельной библиотекой ресурсов.

Единственное, что вам нужно сделать, чтобы использовать ресурсы (изображения, диалоги и т. Д.) В статической библиотеке в Visual C ++ (2008), – это связанный с ними файл .res в вашей статической библиотеке . Это можно сделать в разделе «Настройки проекта / Linker / Input / Additional dependencies».

С помощью этого решения ресурсы статической библиотеки упаковываются в .exe, поэтому вам не нужна дополнительная DLL. К сожалению, Visual Studio не включает файл .res автоматически, как это делает для .lib-файла (при использовании «зависимостей проекта» -feature), но я думаю, что этот небольшой дополнительный шаг является приемлемым.

Я искал очень долгое время для этого решения, и теперь это удивляет меня, что все так просто. Единственная проблема заключается в том, что она полностью недокументирована.

Я просто прошел через это с помощью компилятора MS Visual Studio. Мы конвертировали некоторые устаревшие проекты из DLL в статические библиотеки. В некоторых из этих DLL были встроены диалоговые или строковые ресурсы. Я смог скомпилировать сценарии .RC для этих DLL в нашем основном приложении, включив их в файл сценария RC основного приложения через механизм «TEXTINCLUDE». Мне было проще сделать это, отредактировав RC-файл напрямую, но Visual Studio предоставляет немного более «волшебный» механизм. Реализация, скорее всего, отличается в других компиляторах.


Чтобы напрямую манипулировать основным RC-скриптом:

0,1. В разделе «2 TEXTINCLUDE» укажите файл заголовка, который определяет идентификаторы ресурсов для вашей библиотеки. Синтаксис

 2 TEXTINCLUDE BEGIN "#include ""my_first_lib_header.h""\r\n" "#include ""my_second_lib_header.h""\0" END 

0,2. В разделе «3 TEXTINCLUDE» включите сценарий RC из вашей библиотеки.

 3 TEXTINCLUDE BEGIN "#include ""my_first_library.rc""\r\n" "#include ""my_second_library.rc""\0" END 

Шаги 3 и 4 должны выполняться автоматически, но я обнаружил, что было более надежно просто вводить их самостоятельно, а не в зависимости от компилятора сценариев ресурсов Microsoft, чтобы заботиться о вещах.

0,3. Добавьте файл заголовка с указанием ресурсов ваших библиотек в список только для чтения. Этот список обычно находится в верхней части файла.

 #define APSTUDIO_READONLY_SYMBOLS #include "my_first_lib_header.h" #include "my_second_lib_header.h" #undef APSTUDIO_READONLY_SYMBOLS 

+0,4. Включите RC-скрипт вашей библиотеки в разделе APSTUDIO_INVOKED. Обычно это находится в нижней части файла.

 #ifndef APSTUDIO_INVOKED #include "my_first_library.rc" #include "my_second_library.rc" #endif 

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

  1. Откройте окно «Просмотр ресурсов» в Visual Studio.
  2. Щелкните правой кнопкой мыши файл ресурсов основного приложения и выберите «Resource Includes …» из контекстного меню.
  3. В поле с надписью «Директивы символов только для чтения» добавьте операторы include для файлов .h, которые определяют идентификаторы ресурсов для ваших библиотек.
  4. В поле с надписью «Директивы времени компиляции» добавьте инструкции include для скрипта .rc вашей библиотеки.
  5. Нажмите «ОК». Вы также можете вручную запустить компиляцию RC-скриптов, чтобы убедиться, что это произойдет.

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

Чтобы добавить дополнительный путь include:

  1. Откройте диалоговое окно свойств основного приложения.
  2. Выберите «Свойства конфигурации / Ресурсы / Общие» в левой навигационной панели.
  3. В списке свойств введите любые подходящие пути рядом с «Дополнительные каталоги включения».

Я так не думаю. Статическая библиотека не имеет собственного HINSTANCE. Это код выполняется в контексте DLL или EXE, который связывает его. Вот почему все ресурсы, которые вы попытаетесь загрузить из кода статической библиотеки, будут связаны с библиотекой DLL / EXE.

Я использовал такие ресурсы повторно с DLL, хотя, поскольку у него есть собственное адресное пространство, и вы можете вызвать LoadResource с помощью HINSTANCE DLL.

Рекомендуемый способ – предоставить DLL ресурсы вместе с вашей библиотекой.

Согласно Visual Studio 2010 инструменты разработки Microsoft, по-видимому, не могут должным образом обрабатывать скомпилированные данные ресурсов внутри статических библиотек.

Чтобы распространять скомпилированный файл ресурсов (файл .res ), у вас есть два варианта:

  1. Распространяйте файлы .res отдельно и инструктируйте код клиента для их сопоставления;
  2. Используйте cvtres для объединения нескольких файлов .res файл одного объекта ( .obj ) и укажите его отдельно.

Обратите внимание, что вы не можете lib в объектных файлах, созданных cvtres . Если предоставляется несколько объектных файлов, lib жалуется, как будто было предоставлено несколько файлов .res ; если предоставляется один объектный файл, lib не жалуется, но компоновщик просто игнорирует встроенные данные ресурсов в файле lib.

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

Единственный способ отправить данные ресурсов в статическую библиотеку (в данном случае со статической библиотекой) – это распределить ресурсы по отдельности и явно связать их в клиентском коде. Использование cvtres может сократить количество файлов распределенных ресурсов до одного, если у вас их много.

Когда используется следующий метод, любой ресурс (в этом примере, значок) может использоваться как неотъемлемая часть статической библиотеки, и такая библиотека может использоваться любым типом приложения, включая консольный (который не имеет любой сегмент ресурсов вообще).

  1. Значок преобразуется в статический массив BYTE. bin2c можно использовать для этого.
  2. Данные преобразуются в дескриптор HICON. Вот как я это сделал:

     HICON GetIcon() { DWORD dwTmp; int offset; HANDLE hFile; HICON hIcon = NULL; offset = LookupIconIdFromDirectoryEx(s_byIconData, TRUE, 0, 0, LR_DEFAULTCOLOR); if (offset != 0) { hIcon = CreateIconFromResourceEx(s_byIconData + offset, 0, TRUE, 0x00030000, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); } return hIcon; } 
  3. Вместо LoadIcon используется GetIcon. Вместо того, чтобы звонить:

m_hIcon = ::LoadIcon(hInstanceIcon, MAKEINTRESOURCE(pXMB->nIcon));

Затем позвоните

 m_hIcon = GetIcon() 
Interesting Posts

Spring MVC – HttpMediaTypeNotAcceptableException

Control + Tab больше не работает (Control + Shift + Tab все еще работает)

Каковы причины отказа ICMP на моем сервере?

Как бороться с устаревшими classами в Android для обеспечения совместимости

Как сохранить img на локальный компьютер пользователя с помощью HTML2canvas

OpenCV Birdseye без потери данных

Как установить динамическое имя модели в AngularJS?

Есть ли бесплатный способ сжать PDF?

Android Studio Gradle DSL метод не найден: ‘android ()’ – Ошибка (17,0)

Анти-поддельный токен предназначен для пользователя “”, но текущий пользователь – “имя пользователя”

Включить экранную клавиатуру Windows 8 на настольном ПК

Передача изображения из одной активности другого действия

Тип ошибки 3: Класс активности {…} не существует

Когда Fragment заменяется и помещается в задний стек (или удаляется), он остается в памяти?

curl: (1) Протокол https не поддерживается или отключен в libcurl

Давайте будем гением компьютера.