【问题标题】:How to load a custom binary resource in a VC++ static library as part of a dll?如何在 VC++ 静态库中加载自定义二进制资源作为 dll 的一部分?
【发布时间】:2012-03-03 15:42:47
【问题描述】:

我有自定义二进制资源(动画光标),希望将其作为资源存储在 Visual Studio C++ 的静态库中。事实证明,自定义二进制资源不会被 ::LoadCursor() 加载或被 ::FindResource() 找到,如果它是自定义资源并且在静态库中。

This question 提供一些解决方法。

按照它的建议,如果我将 *.res 文件作为“配置属性->链接器->附加依赖项”添加到 exe,那么静态库将能够找到该资源。

但是,如果静态库是 dll 的一部分,并且我将其作为附加依赖项链接,则不会再次找到它!

如何链接 dll 中的资源?

或者只是在静态库中找到二进制文件?问题中的方法非常繁琐。

【问题讨论】:

  • 目前还不清楚您是否忘记在 DLL 项目中添加所需的 .res 文件。最典型的故障模式是将错误的模块句柄传递给 FindResource()。它必须是 DLL 的模块句柄。你从 DllMain() 中得到它。是的,将它们粘合在一起在设计上很麻烦。

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


【解决方案1】:

在“添加资源”对话框中单击“导入”,选择“所有文件 (.)”,以便您可以导入任何类型的文件,然后在此处选择所需的文件。当自定义资源类型对话框弹出时,在“资源类型”字段中输入 RCDATA。

如果你打开 .rc 文件,你会看到如下内容:

/////////////////////////////////////////////////////////////////////////////
//
// RCDATA
//

IDR_RCDATA1          RCDATA               "myfile.whatever"

它会生成具有以下行的resource.h:

#define IDR_RCDATA1                  101

在代码中你可以这样访问它:

#include "resource.h"
#include <windows.h>

int main(int argc, char* argv[])
{
    HRSRC myResource = ::FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
    HGLOBAL myResourceData = ::LoadResource(NULL, myResource);
    void* pMyBinaryData = ::LockResource(myResourceData);
    return 0;
}

其中 pMyBinaryData 是指向此可执行文件的第一个字节的指针。欲了解更多信息,请访问 Resource Functions

这是一个如何在磁盘上保存二进制资源的示例:

#include "resource.h"
#include <windows.h>
#include <fstream>

int main(int argc, char* argv[])
{
    HRSRC myResource = ::FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
    unsigned int myResourceSize = ::SizeofResource(NULL, myResource);
    HGLOBAL myResourceData = ::LoadResource(NULL, myResource);
    void* pMyBinaryData = ::LockResource(myResourceData);

    std::ofstream f("C:\\x.bin", std::ios::out | std::ios::binary);
    f.write((char*)pMyBinaryData, myResourceSize);
    f.close();

    return 0;
}

当您使用这样的资源构建项目时,该资源将成为您的程序 (dll) 的一部分。

【讨论】:

  • 别忘了解锁资源:BOOL bResult = ::UnlockResource(hRes);bResult = ::FreeResource(hRes);
  • @DitherSky:不。不再需要了,请查看FreeResource function 的文档:"此功能已过时,仅支持向后兼容 16 位 Windows。对于 32-位 Windows 应用程序,无需释放使用 LoadResource 加载的资源。"
  • UnlockResource 只是 SDK 中的一个无操作宏,但奇怪的是 FreeResourcekernel32 上有一个真正的无操作导出用于 backcomp。
  • 如果资源位于调用应用程序内部,则效果很好 - 如果资源位于从其他东西调用的库中, ::FindResource 调用的第一个参数需要是库的模块句柄,其中资源已嵌入 - HRSRC myResource = ::FindResource(hModule, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
  • FindResource的第一个参数是模块。 NULL 将引用进程的 exe。所以这不会加载DLL的资源。
【解决方案2】:

@LihO 答案的问题是:

FindResource的第一个参数是包含资源的Module的ModuleID。如果设置为 NULL,该函数将在创建的进程 (.exe) 中搜索,而不是在 DLL 中搜索。

但是如何在静态 LIB 中获取 HMODULE?

  • 添加一个函数/参数,它将从 DLL 中获取 HMODULE。 HMODULE/HINSTANCE(同上)可以在DLLMain中检索。
  • 试试这个GetCurrentModule

编辑:

另请参阅:Add lib resource to a library

【讨论】:

    【解决方案3】:

    如果您通过 MFC(和 CWinApp)使用 dll,您可以从 CWinApp 获取 HMODULE。

    extern MyDllApp theApp;
    HMODULE module = (HMODULE)theApp.m_hInstance;
    HRSRC myResource = ::FindResource(module,
                MAKEINTRESOURCE(IDR_FILE_RESOURCE), _T("GROUP_NAME"));
    

    如果您在 FindResource 中提供 NULL,应用程序将找不到您的资源。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-17
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多