GetFileVersionInfo失败主因是路径非绝对或资源缺失;须用GetFileVersionInfoSize预检,通过VerQueryValue获取VS_FIXEDFILEINFO后取HIWORD(dwFileVersionMS)得主版本;Unicode路径必用W版API,Release下需确认.rc文件参与编译且未被条件宏屏蔽。

GetFileVersionInfo 调用失败返回 FALSE,但 GetLastError 是 0
这是最常见卡点:函数看似“没报错”,实则根本没读到版本资源。根本原因通常是路径不对或资源不存在。
-
GetFileVersionInfo只能读 PE 文件的VS_VERSIONINFO资源,不是读文件系统属性,也不是读编译时宏定义的字符串 - 传入路径必须是**完整绝对路径**,相对路径(如
"./app.exe")在多数情况下会失败——GetFileVersionInfo不走当前工作目录查找逻辑 - 确保目标 EXE 确实嵌入了版本资源:用
dumpbin /headers your.exe | findstr "resource"或 Resource Hacker 打开确认存在VERSIONINFO类型资源 - 调用前务必先用
GetFileVersionInfoSize获取缓冲区大小,返回 0 就别调GetFileVersionInfo了,否则必然失败
如何从 GetFileVersionInfo 的输出中安全提取主版本号(如 2.1.0.123 中的 2)
不能直接按字符串解析——Windows 版本号是 4×16 位整数(DWORD),存于 VS_FIXEDFILEINFO 结构体里,字节序和结构偏移容易搞错。
- 先用
VerQueryValue查询"\"(根路径)获取VS_FIXEDFILEINFO*指针,不是查"\StringFileInfo\..." - 该结构体中
dwFileVersionMS高 16 位是主版本(HIWORD(dwFileVersionMS)),低 16 位是次版本;dwFileVersionLS同理对应修订号和构建号 - 别用
LOWORD(HIWORD(...))这类嵌套宏——可读性差还易出错,拆成两步:WORD major = HIWORD(info->dwFileVersionMS); - 注意:这个版本号来自资源编译器(RC 编译器)写入的
FILEVERSION,和 C++ 源码里的VERSION_MAJOR宏无关,两者不同步很常见
Unicode 路径下 GetFileVersionInfo 崩溃或返回乱码
本质是字符编码和 API 选择问题:GetFileVersionInfoA 强制 ANSI,GetFileVersionInfoW 才支持宽字符路径,但很多人混用或忽略链接依赖。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须显式调用
GetFileVersionInfoW(带W后缀),且传入LPCWSTR路径,例如L"C:\path\app.exe" - 如果用
TCHAR+TEXT(),确保项目已定义UNICODE和_UNICODE,否则GetFileVersionInfo会退化为 A 版本 -
VerQueryValue返回的字符串指针指向的是资源内存块里的原始字节,若查询"\StringFileInfo\...\ProductName"这类字符串表项,返回值是LPVOID,需强转为LPCWSTR再用,不能当char*处理 - 不要对返回的字符串做
strlen或strcpy——它是宽字符串,长度单位是wchar_t,且不保证以L' '结尾(实际由wLength字段决定)
Release 模式下版本号读出来是 0.0.0.0
不是代码问题,是构建流程断层:资源文件(.rc)没参与 Release 编译,或者版本号宏被条件编译掉了。
立即学习“C++免费学习笔记(深入)”;
- 检查 .rc 文件是否在 Release 配置中被排除(右键 .rc → 属性 → 配置属性 → 常规 → “排除从生成中” 是否为“是”)
- 检查
FILEVERSION行是否被#ifdef DEBUG包裹,例如:#ifdef DEBUG FILEVERSION 1,0,0,0 #else FILEVERSION 0,0,0,0 #endif—— 这会导致 Release 版本号清零 - 确认链接器设置:项目属性 → 配置属性 → 清单工具 → 输入和输出 → “使用清单” 必须为“是”,否则 RC 编译器产出的资源可能未合并进最终 PE
- 一个快速验证法:用
sigcheck -a your.exe(Sysinternals 工具)看输出里是否有ProductVersion和FileVersion字段,没有就说明资源根本没打进去了
版本号不是“写完代码就自动有”的东西,它卡在资源编译、链接、路径解析三个环节上,任一环松动,拿到的就是 0 或崩溃。尤其要注意 Release 配置下 .rc 文件是否真被编译了——这点最容易被忽略。


















