Можно ли создавать ресурсы в статической библиотеке и повторно использовать их, просто связываясь с библиотекой?
Я в первую очередь думаю о случае, когда вы вызываете функцию в библиотеке, которая, в свою очередь, обращается к ресурсам.
Можно ли создавать ресурсы в статической библиотеке и повторно использовать их, просто связываясь с библиотекой?
Я в первую очередь думаю о случае, когда вы вызываете функцию в библиотеке, которая, в свою очередь, обращается к ресурсам.
Это можно сделать, но это довольно болезненно: вы не можете сделать это, просто связавшись со статической библиотекой.
Рассмотрим это: ресурсы встроены в EXE или DLL. Когда какой-то код в статической библиотеке вызывает (например,) LoadIcon, он будет получать ресурсы из EXE или DLL, с которыми он связан.
Итак, если ваша статическая библиотека требует наличия ресурсов, у вас есть несколько вариантов:
CreateDialogIndirect
). См. Raymond Chen "Создание шаблона диалога во время выполнения" .char my_dialog_resource[] = { .... };
, а затем использовать (например,) CreateDialogIndirect
. Вам, вероятно, потребуется найти (или написать) утилиту, которая преобразует файлы .RES
в файлы .CPP
..RC
file) и соответствующим файлом заголовка. Вы тогда #include
их как релевантные. Вам необходимо зарезервировать ряд идентификаторов ресурсов для использования LIB, чтобы они не сталкивались с целями основного EXE или DLL. Это то, что MFC делает, когда используется как статическая библиотека. Или вы можете использовать строковые идентификаторы ресурсов (это не работает для ресурсов STRINGTABLE
).Единственное, что вам нужно сделать, чтобы использовать ресурсы (изображения, диалоги и т.д.) в статической библиотеке в Visual С++ (2008), - это включить связанный с статической библиотекой файл .res в вашем проекте. Это можно сделать в разделе "Настройки проекта /Linker/Input/Additional dependencies".
С помощью этого решения ресурсы статической библиотеки упаковываются в .exe, поэтому вам не нужна дополнительная DLL. К сожалению, Visual Studio не включает файл .res автоматически, как и для .lib файла (при использовании "зависимостей проекта" файла), но я думаю, что этот небольшой дополнительный шаг является приемлемым.
Я искал очень долгое время для этого решения, и теперь это удивляет меня, что все так просто. Единственная проблема заключается в том, что она полностью недокументирована.
Я просто просмотрел это с помощью компилятора 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 визуальной студии, но я обнаружил, что это не всегда применяется, когда я ожидал этого.
Если ваш ресурс библиотеки script ссылается на любые файлы на диске (текстовые файлы, файлы значков и т.д.), вам нужно убедиться, что основной проект приложения знает, где их найти. Вы можете скопировать эти файлы туда, где ваше приложение может их найти, или вы можете добавить дополнительный путь include в настройках компилятора.
Чтобы добавить дополнительный путь include:
Я так не думаю. Статическая библиотека не имеет собственного HINSTANCE. Этот код выполняется в контексте DLL или EXE, который связывает его. Поэтому все ресурсы, которые вы попытаетесь загрузить из статического библиотечного кода, будут включать в себя библиотеку DLL/EXE.
Я использовал повторное использование ресурсов с помощью DLL, хотя он имеет собственное адресное пространство, и вы можете вызвать LoadResource с помощью DLL HINSTANCE.
Рекомендуемый способ - предоставить библиотеку dll ресурсы вместе с вашей библиотекой.
Как и в Visual Studio 2010, средства разработки Microsoft, по-видимому, не могут должным образом обрабатывать скомпилированные данные ресурсов внутри статических библиотек вообще.
Чтобы распространять скомпилированный файл ресурсов (файл .res
), у вас есть два варианта:
.res
по отдельности и указывать код клиента для их сопоставления;cvtres
, чтобы объединить несколько файлов .res
в один объект (.obj
) и предоставить его отдельно.Обратите внимание, что вы не можете использовать lib в объектных файлах, созданных с помощью cvtres
. Если предоставляется несколько объектных файлов, lib
жалуется, как будто было указано несколько файлов .res
; если предоставляется один объектный файл, lib
не жалуется, но компоновщик просто игнорирует встроенные данные ресурсов в файле lib.
Возможно, существует способ заставить компоновщика читать и связывать libbed в данных ресурсов (с некоторыми параметрами командной строки, манипуляциями разделами и т.д.), поскольку данные ресурсов действительно доступны в библиотека (как показывает dumpbin
). До сих пор я не нашел решения, и, если кто-то не хочет взломать инструменты для разработки, ничего лучше этого простого решения, вероятно, не стоит усилий.
Единственный способ отправить данные ресурсов в статическую библиотеку (в данном случае со статической библиотекой) - это распределить ресурсы отдельно и явно связать их в клиентском коде. Использование cvtres
может сократить количество файлов распределенных ресурсов до одного, если у вас их много.
Когда используется следующий метод, любой ресурс (в этом примере, значок) может использоваться как неотъемлемая часть статической библиотеки, и такая библиотека может использоваться любым типом приложения, включая консольный (который не работает у вас нет какого-либо сегмента ресурсов).
Данные преобразуются в дескриптор 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()