从Windows资源文件提取版本信息结果异常的技术求助
从RC资源提取版本信息输出异常的问题分析与修复
环境
Win10、C++20、MSVS Community 17.8.3
问题描述
我尝试从Visual Studio资源编辑器创建并编译生成的.res文件(由.rc文件编译而来,版本资源创建路径:解决方案资源管理器>资源文件>添加>资源>版本)中提取文件版本信息。.rc文件里FILEVERSION和PRODUCTVERSION均设为1, 0, 0, 1,但自己编写的代码运行后输出结果完全不符合预期,编译链接无错误警告。
原代码
#include <iostream> #include <format> #include "resource.h" using std::cout; using std::cerr; using std::endl; using std::format; int main() { struct VersionInfo { DWORD dwFileVersionMS; DWORD dwFileVersionLS; DWORD dwProductVersionMS; DWORD dwProductVersionLS; }; HRSRC hVersionResource = FindResource(NULL, MAKEINTRESOURCE(1), RT_VERSION); if (!hVersionResource) { cerr << "Error: Could not find version resource." << endl; return -1; } HGLOBAL hVersionData = LoadResource(NULL, hVersionResource); if (!hVersionData) { cerr << "Error: Could not load version resource." << endl; return -1; } LPVOID pVersionData = LockResource(hVersionData); if (!pVersionData) { cerr << "Error: Could not lock version resource." << endl; return -1; } VersionInfo* versionInfo = (VersionInfo*)pVersionData; cout << format("File version: {}.{}.{}.{}\n", HIWORD(versionInfo->dwFileVersionMS), LOWORD(versionInfo->dwFileVersionMS), HIWORD(versionInfo->dwFileVersionLS), LOWORD(versionInfo->dwFileVersionLS)); cout << format("Product version: {}.{}.{}.{}\n", HIWORD(versionInfo->dwProductVersionMS), LOWORD(versionInfo->dwProductVersionMS), HIWORD(versionInfo->dwProductVersionLS), LOWORD(versionInfo->dwProductVersionLS)); FreeResource(hVersionData); return 0; }
实际输出
File version: 52.792.86.0 Product version: 95.83.69.86
问题原因
你忽略了RT_VERSION资源的实际结构:
- RT_VERSION资源的起始部分并不是你自定义的
VersionInfo结构体,而是系统定义的VS_VERSION_INFO结构,其中包含了VS_FIXEDFILEINFO和其他可选的字符串信息块。直接强制转换会读取到错误的内存数据,导致输出异常。 - 必须通过
VerQueryValue函数来定位到VS_FIXEDFILEINFO的正确位置,而不是直接强转资源指针。
修复后的代码
#include <iostream> #include <format> #include <windows.h> #include "resource.h" using std::cout; using std::cerr; using std::endl; using std::format; int main() { // 查找版本资源 HRSRC hVersionResource = FindResource(NULL, MAKEINTRESOURCE(1), RT_VERSION); if (!hVersionResource) { cerr << "错误:无法找到版本资源。" << endl; return -1; } // 加载资源 HGLOBAL hVersionData = LoadResource(NULL, hVersionResource); if (!hVersionData) { cerr << "错误:无法加载版本资源。" << endl; return -1; } LPVOID pVersionData = LockResource(hVersionData); if (!pVersionData) { cerr << "错误:无法锁定版本资源。" << endl; return -1; } // 定位VS_FIXEDFILEINFO结构 VS_FIXEDFILEINFO* pFixedFileInfo = nullptr; UINT infoSize = 0; if (!VerQueryValue(pVersionData, L"\\", reinterpret_cast<LPVOID*>(&pFixedFileInfo), &infoSize)) { cerr << "错误:无法查询版本信息。" << endl; return -1; } // 提取并格式化版本号 cout << format("文件版本: {}.{}.{}.{}\n", HIWORD(pFixedFileInfo->dwFileVersionMS), LOWORD(pFixedFileInfo->dwFileVersionMS), HIWORD(pFixedFileInfo->dwFileVersionLS), LOWORD(pFixedFileInfo->dwFileVersionLS)); cout << format("产品版本: {}.{}.{}.{}\n", HIWORD(pFixedFileInfo->dwProductVersionMS), LOWORD(pFixedFileInfo->dwProductVersionMS), HIWORD(pFixedFileInfo->dwProductVersionLS), LOWORD(pFixedFileInfo->dwProductVersionLS)); // 现代Win32系统中无需手动调用FreeResource,系统会自动管理资源 return 0; }
说明
- 修复后的代码使用
VerQueryValue定位根节点\对应的VS_FIXEDFILEINFO结构,这是系统定义的标准版本信息结构,能正确读取到资源中设置的版本号。 - 全程无需手动分配/释放内存,完全基于已加载的资源数据操作,符合你避免原生new[]/delete[]的需求。
- 注意:在现代Win32环境下,
FreeResource函数已经不需要手动调用,系统会自动处理资源释放。
内容的提问来源于stack exchange,提问作者SimpleCoder
相关产品推荐
相关产品推荐

