Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

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

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

  • Вы можете создать библиотеку на лету, а затем использовать (например, CreateDialogIndirect). См. Raymond Chen "Создание шаблона диалога во время выполнения" .
  • Вы можете встроить их в библиотеку в виде простых массивов (т.е.) char my_dialog_resource[] = { .... };, а затем использовать (например,) CreateDialogIndirect. Вам, вероятно, потребуется найти (или написать) утилиту, которая преобразует файлы .RES в файлы .CPP.
  • Вы можете отправить файл LIB с ресурсом script (.RC file) и соответствующим файлом заголовка. Вы тогда #include их как релевантные. Вам необходимо зарезервировать ряд идентификаторов ресурсов для использования LIB, чтобы они не сталкивались с целями основного EXE или DLL. Это то, что MFC делает, когда используется как статическая библиотека. Или вы можете использовать строковые идентификаторы ресурсов (это не работает для ресурсов STRINGTABLE).
  • Ваша статическая библиотека может поставляться с отдельной библиотекой ресурсов.

Ответ 2

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

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

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

Ответ 3

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


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

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 script из вашей библиотеки.

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

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

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 script в разделе APSTUDIO_INVOKED. Обычно это находится в нижней части файла.

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

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

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

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

  • Значок преобразуется в статический массив BYTE. bin2c можно использовать для этого.
  • Данные преобразуются в дескриптор 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;  
    }
    
  • Вместо LoadIcon используется GetIcon. Вместо вызова:

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

Затем вызовите

m_hIcon = GetIcon()