运行《Windows编程》PoePoem程序时触发资源内存访问违规求解决方案
解决Petzold《Windows编程》PoePoem程序内存访问违规问题
问题根源
- 只读内存限制:
LockResource返回的指针指向Windows资源加载后的只读内存区域(内存映射文件的一部分),直接修改该内存会触发内存访问违规——这是Windows资源机制的固有规则,并非20年间的变化,只是旧版系统可能未严格强制执行。 - 字符编码不匹配:Visual Studio 2015默认采用Unicode字符集编译,而原书代码基于ANSI字符集,
char*强制转换和AnsiNext函数在Unicode环境下会导致字符处理逻辑异常,甚至循环无法正确终止。
修复方案
步骤1:将资源内容复制到可写内存
必须先把只读的资源数据复制到可分配的内存块中,再进行修改操作。以下是适配ANSI字符集的代码示例:
HRSRC hResInfo; HGLOBAL hResource; DWORD dwResSize; char* pText; int iNumLines = 0; // 获取资源信息并加载 hResInfo = FindResource(hInst, TEXT("AnnabelLee"), TEXT("TEXT")); dwResSize = SizeofResource(hInst, hResInfo); hResource = LoadResource(hInst, hResInfo); const char* pReadOnlyText = (const char*)LockResource(hResource); // 分配可写内存(+1是为了容纳结束符) pText = (char*)LocalAlloc(LPTR, dwResSize + 1); if (pText == NULL) { // 处理内存分配失败 return 0; } // 复制资源内容到可写内存 memcpy(pText, pReadOnlyText, dwResSize); // 统计行数并修改结束符 char* p = pText; // 注意:原代码中的循环条件应为单引号'\'',修正转义错误 while (*p != '\'' && *p != '\0') { if (*p == '\n') iNumLines++; p = AnsiNext(p); } *p = '\0'; // 后续使用pText处理诗歌内容... // 使用完毕后释放内存 LocalFree(pText);
步骤2:适配Unicode字符集(VS2015默认)
如果你的项目启用了Unicode字符集(项目属性 -> 配置属性 -> 常规 -> 字符集 -> 使用Unicode字符集),需改用宽字符类型处理,避免编码错误:
HRSRC hResInfo; HGLOBAL hResource; DWORD dwResSize; wchar_t* pText; int iNumLines = 0; hResInfo = FindResource(hInst, L"AnnabelLee", L"TEXT"); dwResSize = SizeofResource(hInst, hResInfo); hResource = LoadResource(hInst, hResInfo); const wchar_t* pReadOnlyText = (const wchar_t*)LockResource(hResource); // 分配宽字符可写内存 pText = (wchar_t*)LocalAlloc(LPTR, dwResSize + sizeof(wchar_t)); if (pText == NULL) { return 0; } memcpy(pText, pReadOnlyText, dwResSize); wchar_t* p = pText; while (*p != L'\'' && *p != L'\0') { if (*p == L'\n') iNumLines++; p = Next(p); // 宽字符使用Next函数,或直接p++(固定长度字符) } *p = L'\0'; // 后续处理... LocalFree(pText);
额外注意事项
- 确认
resource.h和.rc文件中资源定义正确,例如.rc中应包含:AnnabelLee TEXT "AnnabelLee.txt" - 若原资源用反斜杠作为结束标记,需将循环条件中的
'\''替换为'\\',确保逻辑匹配资源内容。
内容的提问来源于stack exchange,提问作者Confutus
相关产品推荐
相关产品推荐

