是否可以将资源构建到静态库中,并通过简单地与库链接来重用它们?
我主要考虑的是你在库中调用一个函数然后访问资源的情况。
答案 0 :(得分:56)
在Visual C ++(2008)中,在静态库中使用资源(图像,对话框等),唯一需要做的就是包含静态库的相关.res文件在你的项目中。这可以在“项目设置/链接器/输入/附加依赖性”中完成。
使用此解决方案,静态库的资源将打包到.exe中,因此您不需要额外的DLL。遗憾的是,Visual Studio不会像.lib文件那样自动包含.res文件(当使用“项目依赖项”特性时),但我认为这个额外的小步骤是可以接受的。
我已经花了很长时间才找到这个解决方案,现在让我感到惊讶的是这很简单。唯一的问题是它完全没有记录。
答案 1 :(得分:24)
可以做到,但是非常痛苦:只需链接静态库就无法做到。
考虑这一点:资源嵌入在EXE或DLL中。当静态库中的某些代码调用(例如)LoadIcon时,它将从与其链接的EXE或DLL中获取资源。
因此,如果您的静态库需要资源可用,那么您有几个选择:
CreateDialogIndirect
。见Raymond Chen的"Building a dialog template at run-time"。char my_dialog_resource[] = { .... };
)嵌入到库中,然后使用(例如)CreateDialogIndirect
。您可能需要查找(或编写)将.RES
文件转换为.CPP
个文件的实用程序。.RC
文件)和相应的头文件发送LIB文件。然后,您#include
相关。您需要为LIB保留一系列资源ID,以便它们不会与主EXE或DLL的资源ID冲突。这是MFC用作静态库时的作用。或者您可以使用字符串资源ID(这不适用于STRINGTABLE
资源)。答案 2 :(得分:10)
我刚刚使用MS Visual Studio编译器完成了这项工作。我们将一些遗留项目从DLL转换为静态库。其中一些DLL中嵌入了对话框或字符串资源。通过“TEXTINCLUDE”机制将它们包含在主应用程序的RC脚本文件中,我能够将这些DLL的.RC脚本编译到我们的主应用程序中。我发现通过直接编辑RC文件来实现这一点最简单,但Visual Studio也提供了更多“向导”机制。其他编译器中的实现很可能不同。
直接操作主RC脚本:
0.1。在“2 TEXTINCLUDE”部分中,包含定义库的资源ID的头文件。语法是
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。在APSTUDIO_INVOKED部分中包含库的RC脚本。这通常位于文件的底部。
#ifndef APSTUDIO_INVOKED
#include "my_first_library.rc"
#include "my_second_library.rc"
#endif
您也可以通过Visual Studio IDE自动执行所有这些操作,但我发现它并不总是适用于我预期的。
如果您的库的资源脚本引用磁盘上的任何文件(文本文件,图标文件等),您需要确保主应用程序项目知道在哪里找到它们。您可以将这些文件复制到应用程序可以找到的位置,也可以在编译器设置中添加其他包含路径。
添加其他包含路径:
答案 3 :(得分:1)
我不这么认为。静态库没有它自己的HINSTANCE。它的代码在链接它的DLL或EXE的上下文中执行。这就是为什么你试图从静态库的代码中加载的所有资源都是包含DLL / EXE的资源。
我使用DLL做了那种资源重用,只要它有自己的地址空间,你可以用DLL的HINSTANCE调用LoadResource。
答案 4 :(得分:0)
建议的方法是为dll提供资源以及库。
答案 5 :(得分:0)
根据Visual Studio 2010,Microsoft的开发工具显然无法正确处理静态库中的编译资源数据。
要分发已编译的资源文件(.res
文件),您有两种选择:
.res
个文件,并指示客户端代码链接它们; cvtres
将多个.res
文件合并到一个对象(.obj
)文件中,并单独提供。请注意,您无法使用cvtres
创建的目标文件中的lib。如果提供了多个目标文件,lib
就会抱怨多个.res
文件;如果提供了单个目标文件,lib
不会抱怨,但链接器只是忽略lib文件中的嵌入式资源数据。
可能存在这样一种情况:有一种方法可以强制链接器读取和链接资源数据中的libbed(使用某些命令行选项,部分操作等),因为资源数据确实可用于库(如dumpbin
所示)。到目前为止,我还没有找到解决方案,而且,除非有人愿意破解开发工具,否则任何比这个简单解决方案更好的东西都可能不值得付出努力。
在静态库中发送资源数据的唯一方法(在本例中,带有静态库)是单独分发资源并在客户端代码中显式链接它们。使用cvtres
可以将分布式资源文件的数量减少到一个,如果你有很多。
答案 6 :(得分:-3)
当使用以下方法时,任何资源(在此示例中为图标)都可以用作静态库的组成部分,并且此类库可以被任何类型的应用程序使用,包括控制台(不是没有任何资源段。)
数据转换为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()