win8以上系统中获取系统版本

在win8以上系统中,如win8.1、win10,调用GetVersion()、GetVersionEx()都会返回“6.2 build 9200”,这是win8的版本号,并不是当前系统的,可见微软在这些API中做了手脚,不让我们获取准确的版本号。

做手脚的目的,我猜是为了更好的兼容性,让程序认为自己运行在win8上,而忽略实际是win10这个事实。这样看来,微软也是足够自信啊,自信win10能够完全兼容针对win8系统编写的程序。

咳咳扯远了,我们说回正题。

如果你去msdn上查找GetVersion()的文档,微软会告诉你,这个API已经废弃啦~使用Version Helper APIs代替!Version Helper APIs又是什么鬼?从msdn上可以看到,其中包含IsWindowsXPOrGreater()、IsWindows8OrGreater()、IsWindows10OrGreater()等一系列判断函数,包含在VersionHelpers.h头文件中。

查看VersionHelpers.h文件,发现这些IsWindows*OrGreater()的函数其实都是在调用VerifyVersionInfo(),用VerifyVersionInfo就可以获取准确的版本号吗?经过测试,并不是。。。VerifyVersionInfo依然只能获取当win8的版本号,win8.1开始就返回失败。

继续回去看文档,发现IsWindows8Point1OrGreater文档中有一段特殊的说明:

Applications not manifested for Windows 8.1 or Windows 10 return false, even if the current operating system version is Windows 8.1 or Windows 10. To manifest your applications for Windows 8.1 or Windows 10, see Targeting your application for Windows.

是的,调用这个API还不够!那怎么“target”呢?需要使用manifest文件。这个文件可以手动编辑,也可以在VS中指定编译参数。

在manifest文件中加入下面这一段内容即可:

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
    <application> 
        <!-- Windows 10 --> 
        <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
        <!-- Windows 8.1 -->
        <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
        <!-- Windows Vista -->
        <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
        <!-- Windows 7 -->
        <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
        <!-- Windows 8 -->
        <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
    </application> 
</compatibility>

修改manifest前:
修改manifest前

修改manifest后:
修改manifest后


摔!不就是获取个系统版本号嘛!至于这么麻烦嘛!

然后我就想有没有其他办法。首先想到的是通过系统核心文件的版本号来获取,说到系统核心dll,最核心的应该是ntdll.dll,就拿它下手吧!

操家伙开搞,GetFileVersionInfo读取,然后。。。我擦!微软你要不要这样!hook的这么彻底!FileVersion返回的依然是6.2!看来微软已经想到有人会这么干,提早封了这条路。但是在我想放弃时,突然发现ProductVersion返回的是正确版本,哦呵呵,没封死还留了个洞!

通过系统文件版本来获取是可行的,但看起来不太稳定,说不定哪天微软就真封死了呢,那还有没有其他办法呢?经过一番Google,发现还可以通过PEB这个结构来获取。

PEB(Process Environment Block)看起来挺深奥,貌似是个内核结构,微软并不想用户调用它,相关文档也比较缺乏。最后Google到的结果是,PEB可以通过TEB(Thread Environment Block)来获取,TEB可以通过NtCurrentTeb API来获取,这个API在ntdll.dll中。

然后测试一下,PEB果然是可行的,返回了正确的版本号,但返回的build number貌似有点问题,不过不管了,文档太缺乏,无法深入。


最后总结一下,获取系统版本号的途径有:

  1. GetVersion、GetVersionEx
  2. VerifyVersionInfo
  3. 系统核心文件版本号
  4. PEB

想稳定获取,必须添加manifest文件,通过VerifyVersionInfo判断,这是微软推荐的方法。

附上一个测试时写的易语言代码:VersionHelper

里面引用的模块源码就不发了,都是很简单的模块,可以随意替换。
如果需要对exe添加manifest文件,可以参考:快速修改exe manifest资源

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

扫码去手机上看