Можно ли встроить ресурсы в статическую библиотеку и повторно использовать их, просто связавшись с библиотекой?
Я в первую очередь думаю о случае, когда вы вызываете функцию в библиотеке, которая, в свою очередь, обращается к ресурсам.
Можно ли встроить ресурсы в статическую библиотеку и повторно использовать их, просто связавшись с библиотекой?
Я в первую очередь думаю о случае, когда вы вызываете функцию в библиотеке, которая, в свою очередь, обращается к ресурсам.
Это можно сделать, но это довольно болезненно: вы не можете сделать это, просто связавшись со статической библиотекой.
Учтите следующее: ресурсы встроены в EXE или DLL. Когда какой-то код в статической библиотеке вызывает (например, LoadIcon), он получает ресурсы из EXE или DLL, с которыми он связан.
Итак, если вашей статической библиотеке требуются ресурсы, у вас есть несколько вариантов:
CreateDialogIndirect
. См. «Создание диалогового шаблона во время выполнения» Раймонда Чена. а>.char my_dialog_resource[] = { .... };
), а затем использовать (например) CreateDialogIndirect
. Возможно, вам потребуется найти (или написать) утилиту, которая конвертирует файлы .RES
в файлы .CPP
..RC
файл) и соответствующим файлом заголовка. Затем вы #include
их в зависимости от обстоятельств. Вам необходимо зарезервировать ряд идентификаторов ресурсов для использования LIB, чтобы они не конфликтовали с идентификаторами основного EXE или DLL. Это то, что делает MFC при использовании в качестве статической библиотеки. Или вы можете использовать строковые идентификаторы ресурсов (это не работает для STRINGTABLE
ресурсов).Единственное, что вам нужно сделать, чтобы использовать ресурсы (изображения, диалоги и т. Д.) В статической библиотеке в 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, но я обнаружил, что это не всегда применимо, когда я ожидал.
Если сценарий ресурсов вашей библиотеки ссылается на какие-либо файлы на диске (текстовые файлы, файлы значков и т. Д.), Вам необходимо убедиться, что проект основного приложения знает, где их найти. Вы можете скопировать эти файлы туда, где ваше приложение сможет их найти, или вы можете добавить дополнительный путь включения в настройки компилятора.
Чтобы добавить дополнительный путь включения:
Согласно Visual Studio 2010, инструменты разработки от Microsoft, по-видимому, вообще не могут должным образом обрабатывать скомпилированные данные ресурсов внутри статических библиотек.
Чтобы распространить скомпилированный файл ресурсов (файл .res
), у вас есть два варианта:
.res
файлы отдельно и дайте указание клиентскому коду связываться с ними;cvtres
, чтобы объединить несколько .res
файлов в один объектный (.obj
) файл и предоставить его отдельно.Обратите внимание, что вы не можете использовать lib в объектных файлах, созданных с помощью cvtres
. Если предоставлено несколько объектных файлов, lib
выдает жалобу, как будто было предоставлено несколько .res
файлов; если предоставляется единственный объектный файл, lib
не жалуется, но компоновщик просто игнорирует данные встроенных ресурсов в файле lib.
Возможно, существует способ заставить компоновщик читать и связывать libbed в данных ресурса (с некоторыми параметрами командной строки, манипулированием секциями и т. Д.), Поскольку данные ресурса действительно доступны в библиотеке (как dumpbin
раскрывается). Пока что я не нашел решения, и, если кто-то не хочет взламывать инструменты разработки, ничего лучше этого простого решения, вероятно, не стоит затраченных усилий.
Единственный способ отправить данные ресурсов в статическую библиотеку (в данном случае с статической библиотекой) - раздельно распределить ресурсы и явно связать их в клиентском коде. Использование cvtres
может уменьшить количество файлов распределенных ресурсов до одного, если у вас их много.
Я так не думаю. Статическая библиотека не имеет собственного HINSTANCE. Его код выполняется в контексте DLL или EXE, которые его связывают. Вот почему все ресурсы, которые вы попытаетесь загрузить из кода статической библиотеки, будут из этой включающей DLL / EXE.
Я использовал такие ресурсы повторно с помощью библиотеки DLL, поскольку у нее есть собственное адресное пространство, и вы можете вызвать LoadResource с помощью HINSTANCE библиотеки DLL.
Рекомендуемый способ - предоставить dll с ресурсами вместе с вашей библиотекой.
При использовании следующего метода любой ресурс (в данном примере значок) может использоваться как неотъемлемая часть статической библиотеки, и такая библиотека может использоваться любым типом приложения, включая консольное (которое не имеет любой ресурсный сегмент вообще).
Данные преобразуются в дескриптор 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;
}
GetIcon используется вместо LoadIcon. Вместо звонка:
m_hIcon = ::LoadIcon(hInstanceIcon, MAKEINTRESOURCE(pXMB->nIcon));
Тогда позвони
m_hIcon = GetIcon()