静态库中的VC ++资源

时间:2009-02-10 08:39:49

标签: visual-c++ resources static-libraries

是否可以将资源构建到静态库中,并通过简单地与库链接来重用它们?

我主要考虑的是你在库中调用一个函数然后访问资源的情况。

7 个答案:

答案 0 :(得分:56)

在Visual C ++(2008)中,在静态库中使用资源(图像,对话框等),唯一需要做的就是包含静态库的相关.res文件在你的项目中。这可以在“项目设置/链接器/输入/附加依赖性”中完成。

使用此解决方案,静态库的资源将打包到.exe中,因此您不需要额外的DLL。遗憾的是,Visual Studio不会像.lib文件那样自动包含.res文件(当使用“项目依赖项”特性时),但我认为这个额外的小步骤是可以接受的。

我已经花了很长时间才找到这个解决方案,现在让我感到惊讶的是这很简单。唯一的问题是它完全没有记录。

答案 1 :(得分:24)

可以做到,但是非常痛苦:只需链接静态库就无法做到。

考虑这一点:资源嵌入在EXE或DLL中。当静态库中的某些代码调用(例如)LoadIcon时,它将从与其链接的EXE或DLL中获取资源。

因此,如果您的静态库需要资源可用,那么您有几个选择:

  1. 您可以让库动态构建它们,然后使用(例如)CreateDialogIndirect。见Raymond Chen的"Building a dialog template at run-time"
  2. 您可以将它们作为简单数组(即char my_dialog_resource[] = { .... };)嵌入到库中,然后使用(例如)CreateDialogIndirect。您可能需要查找(或编写)将.RES文件转换为.CPP个文件的实用程序。
  3. 您可以使用资源脚本(.RC文件)和相应的头文件发送LIB文件。然后,您#include相关。您需要为LIB保留一系列资源ID,以便它们不会与主EXE或DLL的资源ID冲突。这是MFC用作静态库时的作用。或者您可以使用字符串资源ID(这不适用于STRINGTABLE资源)。
  4. 您的静态库可以附带单独的资源DLL。

答案 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自动执行所有这些操作,但我发现它并不总是适用于我预期的。

  1. 在Visual Studio中打开“资源视图”窗口。
  2. 右键单击主应用程序的资源文件,然后从上下文菜单中选择“Resource Includes ...”。
  3. 在标有“只读符号指令”的框中,添加.h文件的include语句,用于定义库的资源ID。
  4. 在标有“编译时指令”的框中,添加库的.rc脚本的include语句。
  5. 点击没关系。您可能还想手动触发RC脚本编译,以确保它发生。

  6. 如果您的库的资源脚本引用磁盘上的任何文件(文本文件,图标文件等),您需要确保主应用程序项目知道在哪里找到它们。您可以将这些文件复制到应用程序可以找到的位置,也可以在编译器设置中添加其他包含路径。

    添加其他包含路径:

    1. 打开主应用程序的属性对话框。
    2. 从左侧导航窗格中选择“配置属性/资源/常规”。
    3. 在属性列表中,输入“其他包含目录”旁边的任何相关路径。

答案 3 :(得分:1)

我不这么认为。静态库没有它自己的HINSTANCE。它的代码在链接它的DLL或EXE的上下文中执行。这就是为什么你试图从静态库的代码中加载的所有资源都是包含DLL / EXE的资源。

我使用DLL做了那种资源重用,只要它有自己的地址空间,你可以用DLL的HINSTANCE调用LoadResource。

答案 4 :(得分:0)

建议的方法是为dll提供资源以及库。

答案 5 :(得分:0)

根据Visual Studio 2010,Microsoft的开发工具显然无法正确处理静态库中的编译资源数据。

要分发已编译的资源文件(.res文件),您有两种选择:

  1. 单独分发.res个文件,并指示客户端代码链接它们;
  2. 使用cvtres将多个.res文件合并到一个对象(.obj)文件中,并单独提供。
  3. 请注意,您无法使用cvtres创建的目标文件中的lib。如果提供了多个目标文件,lib就会抱怨多个.res文件;如果提供了单个目标文件,lib不会抱怨,但链接器只是忽略lib文件中的嵌入式资源数据。

    可能存在这样一种情况:有一种方法可以强制链接器读取和链接资源数据中的libbed(使用某些命令行选项,部分操作等),因为资源数据确实可用于库(如dumpbin所示)。到目前为止,我还没有找到解决方案,而且,除非有人愿意破解开发工具,否则任何比这个简单解决方案更好的东西都可能不值得付出努力。

    在静态库中发送资源数据的唯一方法(在本例中,带有静态库)是单独分发资源并在客户端代码中显式链接它们。使用cvtres可以将分布式资源文件的数量减少到一个,如果你有很多。

答案 6 :(得分:-3)

当使用以下方法时,任何资源(在此示例中为图标)都可以用作静态库的组成部分,并且此类库可以被任何类型的应用程序使用,包括控制台(不是没有任何资源段。)

  1. 图标转换为BYTE的静态数组。 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。 而不是打电话:

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

    然后致电

    m_hIcon = GetIcon()