应改用 RtlGetVersion 获取真实系统版本,因其不走应用兼容层、无需 manifest 声明;VerifyVersionInfo 在 Win10/Win11 上默认返回降级版本号(如 6.2),是 Windows 兼容性策略所致。

直接用 VerifyVersionInfo 获取 Windows 系统版本,不仅麻烦、容易出错,而且从 Windows 10 开始已不推荐——它无法正确识别新版系统(比如返回 Windows 8.1 的版本号),除非你显式启用应用兼容清单或调用 SetProcessDpiAwarenessContext 等绕过机制。
为什么 VerifyVersionInfo 在 Win10/Win11 上常返回错误结果
Windows 从 8.1 起引入了“应用兼容性版本策略”:默认情况下,未在 manifest 中声明支持的程序,GetVersionEx 和 VerifyVersionInfo 都会被系统“降级”返回旧版本号(如 6.2 表示 Win8,而非真实的 10.0 或 11.0)。这不是 bug,是设计行为。
常见现象:
- 程序运行在 Windows 11 上,但
VerifyVersionInfo检查VER_MAJORVERSION却得到 6 - 调用
VerifyVersionInfo返回FALSE,但GetLastError()是 0(成功)——说明参数校验失败,但没报具体哪错 - 传入
VER_PRODUCT_TYPE或VER_SUITENAME时逻辑混乱,实际只关心主版本却误配了多个条件位
正确做法:改用 RtlGetVersion(无需 manifest,无兼容性降级)
RtlGetVersion 是内核导出函数,不走应用兼容层,返回真实系统版本。它在 ntdll.dll 中,C++ 可直接动态加载调用。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
实操要点:
- 不要链接
ntdll.lib(它不提供RtlGetVersion的导入符号),必须用GetProcAddress获取地址 - 结构体必须用
OSVERSIONINFOEXW,且dwOSVersionInfoSize必须设为sizeof(OSVERSIONINFOEXW),否则返回失败 - 该函数始终返回 NT 内核版本(如 Win11 22H2 = 10.0.22621),不是 marketing 版本号(“Windows 11”)
- 调用前建议先检查函数是否存在(早期 Win7 SP0 可能未导出,但 Win7 SP1+ 全支持)
简短示例:
HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll");
if (hNtDll) {
using RtlGetVersionFn = NTSTATUS(WINAPI*)(LPOSVERSIONINFOW);
auto pRtlGetVersion = reinterpret_cast<RtlGetVersionFn>(
GetProcAddress(hNtDll, "RtlGetVersion"));
if (pRtlGetVersion) {
OSVERSIONINFOEXW osvi = {};
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (pRtlGetVersion(&osvi) == 0) {
// 成功:osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber
}
}
}
如果非要用 VerifyVersionInfo,必须绕过兼容性限制
仅当项目强依赖旧 API、无法改用 RtlGetVersion 时才考虑。关键不是怎么写判断逻辑,而是怎么让系统“说实话”:
- 在程序 manifest 文件中添加
<supportedOS Id="{8e0f7a12-f815-46c4-9c5c-533ca139357e}"/>(对应 Win10)和 Win11 的 GUID,否则系统拒绝返回真实版本 - 调用前执行
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)(Win10 1703+),部分版本下可间接解除版本伪装 -
VerifyVersionInfo的dwTypeMask别乱 OR:只查主版本就用VER_MAJORVERSION;要同时验证主次版本,必须用VER_MAJORVERSION | VER_MINORVERSION,且lpVersionInfo中对应字段需显式赋值 - 别忘了调用
VerifyVersionInfo前先用ZeroMemory清零整个OSVERSIONINFOEXW结构,未初始化字段会导致校验失败
真正棘手的不是 API 调用本身,而是 Windows 对“未声明兼容性”的静默降级——它不报错,只悄悄给你一个过期答案。多数人卡住,是因为盯着 VerifyVersionInfo 的参数调了半天,却没意识到问题根本不在代码里,而在 manifest 或进程上下文里。

















