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。
【极品模板】出品的一款功能强大、安全性高、调用简单、扩展灵活的响应式多语言企业网站管理系统。 产品主要功能如下: 01、支持多语言扩展(独立内容表,可一键复制中文版数据) 02、支持一键修改后台路径; 03、杜绝常见弱口令,内置多种参数过滤、有效防范常见XSS; 04、支持文件分片上传功能,实现大文件轻松上传; 05、支持一键获取微信公众号文章(保存文章的图片到本地服务器); 06、支持一键
例如:
-
10.0.22621→ Windows 11 22H2 -
10.0.19045→ Windows 10 22H2 -
6.3.9600→ Windows 8.1
微软未提供官方字符串映射 API,GetProductInfo 只能返回 PRODUCT_PROFESSIONAL 这类枚举,不带年份/代号。所以实际项目中建议维护一个轻量静态表,按 dwBuildNumber 区间判断(比只看主次版本更准):
if (osvi.dwMajorVersion == 10 && osvi.dwBuildNumber >= 22000) {
return "Windows 11";
} else if (osvi.dwMajorVersion == 10) {
return "Windows 10";
} else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) {
return "Windows 8.1";
}Build number 是唯一稳定标识,比如 10.0.19041 和 10.0.19045 都是 Win10 2004/20H2,但后者是累积更新版本——用 Build 判断兼容性比拼凑字符串靠谱得多。
VerifyVersionInfo 失败的典型错误现象
直接调用 VerifyVersionInfo 返回 FALSE 却没报错,是最常见的迷雾现场。常见原因包括:
-
VerSetConditionMask返回值未用于dwTypeMask,导致传入 0 —— 系统认为“不关心任何条件”,直接拒绝 -
OSVERSIONINFOEX中未初始化所有字段(尤其是wServicePackMajor、wSuiteMask),未设的字段是栈垃圾值,比较必然失败 - 忘记调用
ZeroMemory(&osvi, sizeof(osvi)),dwOSVersionInfoSize字段残留随机值 - 在非 UI 线程(如 DLL_PROCESS_ATTACH)中首次调用,触发内部 GDI 初始化失败,间接导致验证失败
这些细节一旦漏掉,VerifyVersionInfo 就像个哑巴函数,既不崩溃也不报错,只默默返回 FALSE。调试时务必检查 GetLastError(),它通常会返回 ERROR_OLD_WIN_VERSION 或 ERROR_INVALID_PARAMETER。









