【问题标题】:FindResource call returns NULL for text file with type RCDATAFindResource 调用为 RCDATA 类型的文本文件返回 NULL
【发布时间】:2019-07-18 22:04:48
【问题描述】:

我正在编写一个 C++ 程序,它需要处理大量数据,特别是文本文件,但是数据长于给定的字符串限制。结果,我尝试将文本文件加载为资源文件,但是每当我调用 FindResource 时,响应都是空句柄。

我已经查看了其他堆栈溢出帖子,并且 MSDN 尝试正确实现此功能,但是我尝试过的没有返回有效句柄。

C++ 代码:

HGLOBAL     res_handle = NULL;
HRSRC       res;
char *      res_data;
DWORD       res_size;

auto g_hInstance = GetModuleHandle(NULL);
res = FindResource(g_hInstance, MAKEINTRESOURCE(MY_RESOURCE), RT_RCDATA);
std::cout << res << std::endl;
std::cout << GetLastError() << std::endl;
res_handle = LoadResource(NULL, res);
std::cout << GetLastError() << std::endl;
res_data = (char*)LockResource(res_handle);
std::cout << GetLastError() << std::endl;
res_size = SizeofResource(NULL, res);
std::cout << GetLastError() << std::endl;

输出:

0000000000000000
1813
87
87
87

资源.h:

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Resource.rc
//
#define MY_RESOURCE 300
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40002
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

资源.rc:

MY_RESOURCE RCDATA "C:\\Users\\foobar\\Desktop\\projects\\foobar\\test0.txt"

【问题讨论】:

  • 将 int 更改为名称并在不使用 MAKEINTRESOURCE 的情况下使用它。
  • 您可以在您的 EXE 中检查资源。在 Visual Studio 中,执行 File &gt; Open &gt; File,选择您的 EXE,然后单击打开按钮旁边的小箭头并选择 Open With &gt; Resource Editor。检查您要查找的资源是否确实存在。很可能,问题出在构建上。
  • 感谢 Igor 的评论,在 Visual Studio 中,我可以在资源文件 -> Resource.rc -> RCDATA 中看到实际资源。除非我弄错了你的意思。
  • 我将您建议 Michael 的代码行更改为“res = FindResource(g_hInstance, (LPCTSTR)MY_RESOURCE, RT_RCDATA);”并得到相同的输出。
  • 就像我说的,检查资源是否实际存在于您的项目构建的 EXE 文件中。

标签: c++ windows embedded-resource


【解决方案1】:

这对我有用。我怀疑您的构建设置出了点问题。

我从 Visual Studio 2017 中的一个空项目开始,我在项目设置中唯一更改的是配置属性 > 常规 > 字符集 > “使用 Unicode 字符集”

来源.cpp

#include <iostream>
#include <Windows.h>
#include "resource.h"

int main() {
  auto hinst = ::GetModuleHandleW(NULL);
  std::cout << hinst << std::endl;
  auto hrsrc = ::FindResourceW(hinst, MAKEINTRESOURCE(IDTHING), RT_RCDATA);
  std::cout << hrsrc << std::endl;
  auto hglob = ::LoadResource(hinst, hrsrc);
  std::cout << hglob << std::endl;
  return 0;
}

资源.h

#define IDTHING 300

资源.rc

#include "resource.h"

IDTHING RCDATA "C:\\Windows\\notepad.exe"

我完全避免了所有来自 VS 的自动生成的资源内容,只是将它们写为纯文本文件。

如果你在调试器中运行,在hglob被赋值后停止并将其值放入内存窗口,我可以清楚地看到notepad.exe的PE头。

【讨论】:

    【解决方案2】:

    当您从 GetLastError() 收到错误代码时,您应该调用 FormatMessage API(带有 FORMAT_MESSAGE_FROM_SYSTEM 标志)或使用错误查找工具,Visual Studio 中的“工具/错误查找”。

    代码 1813 转换为以下消息:“在图像文件中找不到指定的资源类型。”

    如您所见,它抱怨资源 type

    我认为你不需要 RCDATA。从 16 位 Windows 来看,这是非常古老的东西。在 Win32 中,自定义资源类型是字符串,而不是整数。 IDE 甚至不支持 RCDATA。

    正确的方法——右击你的 .rc 文件,“添加资源”,“导入”,浏览你想要包含的文件,Visual Studio 会询问你的资源类型,写任何字符串,例如text 可以,然后将该字符串作为 FindResource 函数的最后一个参数传递。如果您使用默认项目设置进行构建,则它是 Unicode,因此您需要在此处传递 Unicode 字符串 L"text"

    【讨论】:

    • 使用RCDATA没有任何问题。它不是“旧的”,它是官方支持和本地定义的资源类型,许多现代应用程序仍在使用它。
    • @RemyLebeau 它没有暴露在 Visual Studio 的资源编辑器 GUI 中。当以正确的方式手动破解源文件时,它很可能仍然有效,但 Visual Studio 希望将字符串名称用于自定义资源类型。
    • @RemyLebeau 从技术上讲是的,但实际上,自从 MS 在 2015 年发布了功能齐全的 VS 社区版以来,我认为这些其他 IDE 仍然不相关。至少对于 C++ 来说不是。
    • @RemyLebeau 很好,但 OP 显然可以:Microsoft Visual C++ generated include file.
    猜你喜欢
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    相关资源
    最近更新 更多