Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

Единственное, что вам нужно сделать, чтобы использовать ресурсы (изображения, диалоги и т.д.) В статической библиотеке в Visual C ++ (2008), это включите связанный со статической библиотекой файл .res в вашем проекте.Это можно сделать в разделе "Настройки проекта / Компоновщик / Ввод / Дополнительные зависимости".

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

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

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


Для непосредственного управления основным RC-скриптом:

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

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

.2.В разделе "3 TEXTINCLUDE" включите RC-скрипт из вашей библиотеки.

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

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

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

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

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

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

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

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

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

Чтобы добавить дополнительный включаемый путь:

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

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

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

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

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

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

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

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

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

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

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

  1. Значок преобразуется в статический массив из байт. 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. GetIcon используется вместо LoadIcon.Вместо того, чтобы звонить:

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

Тогда звони

m_hIcon = GetIcon()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top