vc中如何使用静态库的资源

来源:互联网 发布:海思科技人工智能 编辑:程序博客网 时间:2024/06/05 14:51
最近做的项目,需要将所有工程依赖的dll动态库以静态库lib的方式提供。其中用到一些纯资源的dll库,没有任何代码,没有entry入口。一开始,将资源dll简单的重新编译成lib文件库,发现无法链接到工程里。通过大量baidu,实验,终于解决了问题。这篇博客将找到的相关文章记录下来,以方便未来温习,回顾。+++++++++++++++++++++++++++++++最近在使用静态库的时候,发现静态库不能带资源,在使用的时候静态库查找自带资源的时候会报错,看了下MSDN:“If you add an rc file to a static library, you may experience difficulties due to the limitation that only one rc file may be present in a Dll or Exe. This problem may be overcome by including the library's .rc file into the parent project's .rc file.” (如果你想为一个静态库添加资源文件,你会遇到困难。因为在DLL或EXE中只能存在一个资源文件(见后面注释)。你可以通过将静态库的资源文件加入到你自己的工程资源文件中来解决这个问题。)1:选择 view —— Resource Includes

在Resource Includes对话框中,在Read-only symbol directives中添加资源头文件,afxres等。

在Compile-time directives中添加资源文件,rc文件及其相对路径



2:
添加导入的资源文件目录,因为资源文件中一般是使用的相对路径。Project —— Settings, 选择Project Settings对话框中的Resources, 在Additional resource Include directories中添加导入的资源文件目录。

 
注:1.资源文件是*.rc文件,不包括rc2,rc3等文件.
2.lib文件里无法包含rc文件。
3.exe或dll文件只能包含一个rc文件。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


以下是overflow的内容:
ask:

Is it possible to build resources into a static library and reuse them by simply linking with the library?

I'm primarily thinking about the case where you call a function in the library which in turn accesses resources.

answer:

<1>

It can be done, but it's quite painful: You can't do it by simply linking with the static library.

Consider this: resources are embedded in an EXE or DLL. When some code in the static library calls (e.g.) LoadIcon, it'll get the resources from the EXE or DLL that it's linked with.

So, if your static library requires resources to be available, you've got a couple of options:

  1. You can have the library build them on the fly, and then use (e.g.) CreateDialogIndirect. See Raymond Chen's "Building a dialog template at run-time".
  2. You can have them embedded in the library as simple arrays (i.e.) char my_dialog_resource[] = { .... };, and then use (e.g.) CreateDialogIndirect. You'll probably need to find (or write) a utility that converts from .RES files to .CPP files.
  3. You can ship the LIB file with a resource script (.RC file) and corresponding header file. You then #include them as relevant. You'll need to reserve a range of resource IDs for the LIB to use, so that they don't collide with those of the main EXE or DLL. This is what MFC does when used as a static library. Or you can use string resource IDs (this doesn't work for STRINGTABLE resources).
  4. Your static library can ship with a separate resource DLL.

<2>

The only thing you need to do to use resources (images, dialogs, etc...) in a static library in Visual C++ (2008), is include the static library's associated .res file in your project. This can be done at "Project settings/Linker/Input/Additional dependencies".

With this solution, the resources of the static library are packed into the .exe, so you don't need an extra DLL. Regrettably, Visual Studio does not include the .res file automatically as it does for the .lib file (when using the "project dependencies"-feature), but I think this small extra step is acceptable.

I have looked for a very long time for this solution, and now it surprises me it is that simple. The only problem is that it is totally undocumented.

<3>

I just went through this with the MS Visual Studio compiler. We were converting some legacy projects from DLLs into static libraries.

Several of these DLLs had dialog or string resources embedded in them. I was able to compile the .RC scripts for these DLLs into

our main application by including them in the main application's RC script file via the "TEXTINCLUDE" mechanism.

I found it easiest to do this by editing the RC file directly, but Visual Studio provides a slightly more "wizardy" mechanism as well.

The implementation is most likely different in other compilers.


To manipulate the main RC script directly:

.1. In the "2 TEXTINCLUDE" section, include the header file that defines the resource IDs for your library. The syntax is

2 TEXTINCLUDE BEGIN    "#include ""my_first_lib_header.h""\r\n"    "#include ""my_second_lib_header.h""\0" END

.2. In the "3 TEXTINCLUDE" section, include the RC script from your library.

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

Steps 3 and 4 should happen automatically, but I found it was more reliable to just enter them myself, rather than depending on Microsoft's resource script compiler to take care of things.

.3. Add the header file with your libraries resource defines to the read only symbols list. This list is usually near the top of the file.

#define APSTUDIO_READONLY_SYMBOLS#include "my_first_lib_header.h"#include "my_second_lib_header.h"#undef APSTUDIO_READONLY_SYMBOLS

.4. Include your library's RC script in the APSTUDIO_INVOKED section. This is usually at the bottom of the file.

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

You can also do all of this automatically through the visual studio IDE, but I found it didn't always apply when I expected it to.

  1. Open the "Resource View" window in Visual Studio.
  2. Right-click on your main application's resource file and choose "Resource Includes..." from the context menu.
  3. In the box labeled "Read-only symbol directives," add the include statements for the .h files that define the resource ID's for your libraries.
  4. In the box labeled "Compile-time directives," add the include statements for your library's .rc script.
  5. Click okay. You may also want to manually trigger the RC script compilation, to make sure it happens.

If your library's resource script references any files on disk (text files, icons files, etc.), you'll need to make sure that the main application project knows where to find them. You can either copy these files to somewhere your application can find them or you can add an additional include path in the compiler settings.

To add an additional include path:

  1. Open up the properties dialog for your main application.
  2. Select "Configuration Properties/Resources/General" from the left-hand navigation pane.
  3. In the properties list, Enter any pertinent paths next to "Additional Include Directories."

<4>

As per Visual Studio 2010, the development tools from Microsoft apparently cannot properly handle compiled resource data inside static libraries at all.

To distribute a compiled resource file (a .res file), you have two choices:

  1. Distribute the .res files separately, and instruct the client code to link against them;
  2. Use cvtres to merge several .res files into a single object (.obj) file, and provide it separately.

Note that you can't lib in object files created with cvtres. If multiple object files are provided, lib complains as though as multiple .res files were given; if a single object file is provided, lib does not complain, but the linker simply ignores the embedded resource data in the lib file.

It might be the case that there is a way to force the linker to read and link the libbed in resource data (with some command-line option, section manipulation and so on), since the resource data is indeed available in the library (as dumpbin reveals). So far, I haven't found a solution, and, unless one is willing to hack the development tools, anything better than this simple solution is probably not worth the effort.

The only way to ship resource data in a static library (in this case, with a static library) is to distribute the resources separately and explicitly link them in the client code. Using cvtres can reduce the number of distributed resource files to one, if you have many of them.



0 0