VerifyVersionInfoW 优于 VerifyVersionInfoA,因后者受 ANSI 编码和区域设置影响;但二者均需配合 VerSetConditionMask 且受 manifest 限制,推荐优先使用不受限的 RtlGetVersion 获取真实系统版本。
VerifyVersionInfoA 和 VerifyVersionInfoW 的区别与选择
Windows 提供的 VerifyVersionInfoA 和 VerifyVersionInfoW 是同一 API 的 ANSI/Unicode 版本,但实际使用中几乎没人直接调用它们——因为从 Windows 8.1 开始,微软明确要求必须配合 VerSetConditionMask 使用,且 OSVERSIONINFOEX 结构体字段需严格初始化,否则返回 FALSE 即使系统满足条件。
更关键的是:自 Windows 10 1607 起,VerifyVersionInfo 在应用未声明兼容性时会被系统静默降级为 Windows 8.1 版本号(即返回 dwMajorVersion=6, dwMinorVersion=3),哪怕你真在 Win11 上跑。
- 必须在 manifest 中声明支持目标系统,例如添加
(Win10)或对应 Win11 GUID -
dwOSVersionInfoSize字段必须设为sizeof(OSVERSIONINFOEX),漏设会导致调用失败 - 推荐优先用
VerifyVersionInfoW,避免 ANSI 编码路径下区域设置引发的不可靠比较
比 VerifyVersionInfo 更可靠的做法:RtlGetVersion
RtlGetVersion 是内核导出函数,不走 UAC 兼容层,也不受 manifest 限制,返回真实内核版本。它在 ntdll.dll 中,无需 manifest 声明,且从 Windows XP 到 Windows 11 全系可用。
注意它不是公开 Win32 API,头文件不声明,需手动 GetProcAddress 获取函数指针:
立即学习“C++免费学习笔记(深入)”;
typedef NTSTATUS(NTAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
RtlGetVersionPtr pRtlGetVersion = (RtlGetVersionPtr)GetProcAddress(hNtDll, "RtlGetVersion");
RTL_OSVERSIONINFOW osvi = {0};
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (pRtlGetVersion && pRtlGetVersion(&osvi) == 0) {
// osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber 可信
}
- 返回值为
NTSTATUS,成功是0(STATUS_SUCCESS),不是布尔值 -
RTL_OSVERSIONINFOW和OSVERSIONINFOW字段布局一致,但前者是 ntdll 内部结构,不能混用 typedef - 不需要
#include或链接ntdll.lib,纯运行时绑定即可
获取带具体版本名(如 “Windows 11”)的字符串
RtlGetVersion 只给数字版号,要转成用户可读名称,得查表匹配:dwMajorVersion + dwMinorVersion + dwBuildNumber 组合决定具体 SKU。