关于 GetVersion 系列接口
关于如何获取 Windows 系统版本号的话题,网上已经有了太多的帖子。但个人觉得总结的都不尽全面,或者没有给出比较稳定的解决方案。
众所周知,获取 Windows 系统版本的 API 是 GetVersion 和 GetVersionEx。这两个 API 的使用也都相当简单,一直被广泛使用 (下文中,我们将这两个统称为 GetVersion 系列)。后来在 Windows XP 中微软引入了应用程序兼容模式,可以选择兼容之前老的系统。可能很多人并不知道其具体的实现原理,以及能造成如何影响,微软官网开始也未对此详细说明。但直到后来,随着 Windows Vista、Windows 7 等发布,开始有人在网上反映这个 API 并不能获取到真正的系统版本号,我也尝试过测试各种获取系统版本信息的 API,才慢慢发现应用兼容性设置其中一个影响就是获取到错误的系统版本号。即,将程序设置为兼容旧的操作系统,则 GetVersion 系列接口获取到的版本就是该兼容系统的版本,也就是与当前系统实际版本不符,是错误的。
与此同时,Windows XP 中也引入了主题,引入了 manifest 文件 (Visual Studio 中称之为清单文件) 的概念。关于这个清单文件,我在这篇文章中讨论程序执行权限也提到过,此文暂不详述。清单文件中的设置会影响到程序的某些行为,比如是否使用主题、是否以管理员权限执行、程序支持的操作系统列表、是否受 DPI 缩放影响等。这里我们只讨论其中“支持的操作系统列表”这部分,因为这部分现在也会影响到在新版操作系统中调用 GetVersion 系列的结果。
虽然微软的官网对于该系列 API 的行为进行了说明,但毕竟实践才是唯一标准。为了搞清楚各个系统版本的 GetVersion 系列接口结果行为有何不同,我详细测试后,将其整理如下:
是否嵌入清单
程序无清单文件或清单未指定支持当前系统
程序有清单文件且清单指定支持当前系统
兼容模式设置
未设置兼容模式
设置兼容模式
未设置兼容模式
设置兼容模式
Windows 2000
5.0
5.0[1]
5.0[2]
5.0[2]
Windows XP (x86)
5.1
兼容模式设置的兼容系统版本
5.1[3]
5.1[3]
Windows XP (x64)
5.2
兼容模式设置的兼容系统版本
5.2[3]
5.2[3]
Windows Vista
6.0
兼容模式设置的兼容系统版本
6.0
兼容模式设置的兼容系统版本
Windows 7
6.1
兼容模式设置的兼容系统版本
6.1
兼容模式设置的兼容系统版本
Windows 8
6.2
兼容模式设置的兼容系统版本,最高 6.2。
6.2
兼容模式设置的兼容系统版本,最高 6.2。
Windows 8.1
6.2
兼容模式设置的兼容系统版本,最高 6.2。
6.3
兼容模式设置的兼容系统版本,最高 6.3。
Windows 10
6.2
兼容模式设置的兼容系统版本,最高 6.2。
10.0
兼容模式设置的兼容系统版本,最高 10.0。
[1] Windows 2000 不支持兼容模式,因此结果不受影响。
[2] Windows 2000 不支持清单文件,因此结果不受影响。
[3] Windows XP 不支持清单文件中指定的支持操作系统列表。
可以看得出来,结果惨不忍睹,这还怎么能让人放心使用?实际上 GetVersion 系列接口的行为变更从 XP 时代就有了,然而微软开始并没有在 MSDN 上给出相关提示,也没有多少人留意。起初微软是为了设置应用程序以兼容模式运行,将其 hook 并返回错误的结果,这个反而带来了更大的麻烦,再加上 manifest 的引入,使得这个 API 完全被微软玩坏。到 Windows 8 时代,该页面才注明该 API 已被废弃,并且给出其他的解决方案。只能说,这两个 API 走到今天这条路,微软也是没办法,这个行为一开始被修改就注定了今天被抛弃的结果。
官方推荐的备用方案
此外,微软也提供其他的几个 API 用来判断 (不能获取) 系统版本是否为特定版本,只是鲜为人知,使用频率较低。从 GetVersion 系列被抛弃开始,这些 API 才在 MSDN 被列出在 GetVersionEx 的说明页面,作为其他的备选方案。
IsOS
这个 API 是判断特定版本的,但是最高支持也就到 Windows 2003。此后,微软 MSDN 页面未对参数进行更新。
VerifyVersionInfo
该 API 要求配合 VerSetConditionMask 使用,才能进行后续判断。微软已经将 VerifyVersionInfo 封装为更易使用的函数。使用这些函数需包含 VersionHelpers.h 头文件,只有安装了较新版本的 Visual Studio 或 Windows SDK 才支持。
IsWindowsXPOrGreater
IsWindowsXPSP1OrGreater
IsWindowsXPSP2OrGreater
IsWindowsXPSP3OrGreater
IsWindowsVistaOrGreater
IsWindowsVistaSP1OrGreater
IsWindowsVistaSP2OrGreater
IsWindows7OrGreater
IsWindows7SP1OrGreater
IsWindows8OrGreater
IsWindows8Point1OrGreater
要求程序已嵌入清单文件且清单指定支持 Windows 8.1 及更高版本系统,否则返回 false。
IsWindows10OrGreater
要求程序已嵌入清单文件且清单指定支持 Windows 10 及更高版本系统,否则返回 false。