LoadString返回空字符串、FindResource报1814错误的问题排查
问题核心原因
你遇到的资源找不到错误,本质是对Win32 STRINGTABLE 资源的存储规则不熟悉、资源脚本写法或API调用存在错误导致的,FindResource返回1814并不完全代表资源没编译进去,你之前的FindResource调用写法本身就是错误的。
Win32平台的字符串资源不是按单个ID独立存储的,系统会把每16个连续ID的字符串打包成一个资源块:
- 资源块的ID计算公式为
(字符串ID / 16) + 1 - 单个字符串在块内的存储位置由
字符串ID % 16决定 - 你直接传
MAKEINTRESOURCE(POSITIONS_ID)给FindResource,实际查找的是第10号资源块,对应ID范围是144159的字符串,和你ID=10的字符串所在的1号块(对应ID015)完全不匹配,必然返回资源不存在。
修复步骤
按以下顺序排查,绝大多数同类问题都能解决:
修正资源脚本写法
检查你的.rc文件,确保STRINGTABLE块写法符合规范,注意几个容易踩的坑:- 必须正确包含定义
POSITIONS_ID的resource.h头文件,宏定义必须是纯数值,不能带表达式,正确的头文件定义参考:// resource.h #define POSITIONS_ID 10 - STRINGTABLE块要带默认的
DISCARDABLE属性,手动写资源脚本很容易漏这个属性:#include "resource.h" STRINGTABLE DISCARDABLE { POSITIONS_ID "100 100 \ 200 350 \ 400 800" } - 多行字符串的续行反斜杠
\必须是行尾最后一个字符,后面不能跟空格、注释等任何内容,否则资源编译器会识别续行失败。 - 确认.rc文件已经加入项目的资源编译列表,没有被设置为“从生成中排除”。
- 必须正确包含定义
修正LoadString调用参数
不要给LoadString第一个参数传NULL,NULL代表从系统模块加载资源,不是你自己的程序模块。必须传入当前模块的实例句柄:- EXE程序直接用
WinMain入口函数传入的hInstance参数 - DLL模块用
DllMain入口传入的hInstance参数 GetModuleHandle(NULL)只能拿到EXE的句柄,如果资源写在DLL里,传这个值一样会找不到资源
正确的调用示例:
// hInstance 为当前模块的实例句柄 wchar_t data[100] = {0}; // Windows原生字符串资源为宽字符,优先用W版本API避免编码问题 int len = LoadStringW(hInstance, POSITIONS_ID, data, 100); if (len > 0) { // 读取成功,data里就是存储的字符串内容 }- EXE程序直接用
正确验证资源是否存在
不要用之前错误的FindResource写法验证,正确查找ID=10字符串所在资源块的代码如下:UINT blockId = (POSITIONS_ID / 16) + 1; HRSRC hRes = FindResourceW(hInstance, MAKEINTRESOURCEW(blockId), RT_STRING); if (!hRes) { // 这时候返回1814才是真的资源没编译进二进制 DWORD err = GetLastError(); }
内容的提问来源于stack exchange,提问作者Zeritonik
相关产品推荐
相关产品推荐

