FindResource() 函数失败,尽管资源存在

Posted

技术标签:

【中文标题】FindResource() 函数失败,尽管资源存在【英文标题】:FindResource() function fails although resource exists 【发布时间】:2016-01-28 13:28:17 【问题描述】:

我正在尝试使用 Win32 FindResource() 函数将嵌入式资源加载到缓冲区中。 我在 Visual Studio 2015 IDE 中添加资源编译时间:

正如您使用 CFFexplorer 或 ResHacker 等 PE 编辑器所见,资源已正确添加:

当我尝试使用 FindResource() 函数在运行时加载它时,即在 DLL 项目开始时出现问题:

  INT WINAPI DllMain( HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved )

    HRSRC ResLocation = 0;

    switch( dwReason ) 
     
        case DLL_PROCESS_ATTACH:

            // Show debug console
            AllocConsole();
            freopen("CONOUT$", "w", stdout);  

            //Locate our resource
            ResLocation = FindResource(hInstDLL, "RESFILE", "RESFILE");

            // FindResource returns NULL with error 1813: ERROR_RESOURCE_TYPE_NOT_FOUND
            printf("TEST RESULT: reslocation: %i error %i\n", ResLocation, GetLastError());

            StartProc();
            break;
        case DLL_PROCESS_DETACH:
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
    
    return 1;

FindResource 返回 NULL,错误 1813:ERROR_RESOURCE_TYPE_NOT_FOUND。 关于为什么它无法加载资源的任何想法? 谢谢

【问题讨论】:

你应该DllMain做所有这些! AllocConsole 是一个明显的禁忌。 为什么不呢?请您详细说明一下 @FlavioM.Foglia:DLLMain 不应该做任何可能导致加载更多代码、同步对象被锁定等的事情。msdn.microsoft.com/en-us/library/windows/desktop/… 阿德里安报道了它。一般规则是在DllMain 中基本上什么都不做,只是为了安全起见。该文档包含一个明确禁止的列表,但调用任何复杂的 API 或第三方代码本质上是棘手的,因为您无法知道 它们 做什么。目标是保持DllMain 为空存根,对所有内容使用延迟初始化。如果您绝对需要做更多事情,请让您的 DLL 提供并导出应用程序将调用的 Initialize(或类似)函数。 Windows 库都是这样做的,例如 COM、GDI+ 等。 【参考方案1】:

我发现了问题所在。

有另一个可执行文件在运行时在同一个 dll 上写入了另一个资源。 它使用 BeginUpdateResource() 完成此操作。

问题出在 BeginUpdateResource() 第二个参数,它设置为 true:添加新资源时,它会删除我在设计时添加的旧资源。将此参数设置为false,解决了我的问题。

【讨论】:

【参考方案2】:

FindResource()/LoadResource() 是 AFAIK 不是查找/加载整个资源“文件”(事实上没有这样的文件,资源嵌入在 dll 中),而是一个特定的资源(字符串,资源 src 文件指定的位图、图标等)。

“RESFILE”不是允许的资源类型,列表见ResourceTypes。

【讨论】:

是的,我知道,但也可以添加和加载可能包含任意数据的自定义命名资源【参考方案3】:

看来你的第三个参数是错误的。

来自 MSDN:

HRSRC WINAPI FindResource(
  _In_opt_ HMODULE hModule,
  _In_     LPCTSTR lpName,
  _In_     LPCTSTR lpType
);

lpType [输入]

资源类型。或者,而不是 一个指针,这个参数可以是 MAKEINTRESOURCE(ID),其中 ID 是 给定资源类型的整数标识符。对于标准资源 类型,请参阅Resource Types。有关详细信息,请参阅备注 下面的部分。

使用上面的链接查找您的资源类型并使用它而不是“RESFILE”。

例如

ResLocation = FindResource(hInstDLL, "RESFILE", MAKEINTRESOURCE(RT_VERSION));

【讨论】:

试过了,但我收到错误 1814:ERROR_RESOURCE_NAME_NOT_FOUND。虽然我正确地定义了它并且资源被正确地添加到 PE 文件中。 ' #define IDR_RCDATA1 104 ResLocation = FindResource(hInstDLL, MAKEINTRESOURCE(IDR_RCDATA1), MAKEINTRESOURCE(RT_RCDATA));' @Flavio RT_VERSION 是一个已经定义为MAKEINTRESOURCE(16) 的宏,因此无需再次将其传递给MAKEINTRESOURCE

以上是关于FindResource() 函数失败,尽管资源存在的主要内容,如果未能解决你的问题,请参考以下文章

FindResource() 的问题

将EXE作为资源,然后在释放到磁盘上并运行该exe程序(使用了FindResource,LoadResource,然后用CFile写成一个文件)

win32释放资源

如何使用 Windows Native API 访问 PE 资源?

尽管有大量可用内存,但 malloc() 失败

Jackson 因“无法构造 WorkpoolId 的实例(尽管至少存在一个 Creator)而失败:没有 int/Int-argument 构造函数/工厂”