获取Windows版本的可靠方法:VerQueryValue
acmilan2017/04/22软件综合 IP:四川

自从Windows 8.1废弃了GetVersionEx,必须写manifest才能正确获取系统版本之后,如何始终正确获取系统版本就是一个让人头疼的话题。大概有以下几种尝试。

  • 尝试使用VerifyVersionInfo——实际上是没读懂微软的文档,这个函数也会被manifest影响
  • 使用RtlGetVersion——早在XP时代就被很多人用于防止兼容模式了,所以Vista以后兼容模式也hook掉了,虽然不需要manifest,但是不保证以后还能用
  • 使用RtlGetNtVersionNumbers——至今未文档化的函数,不推荐

实际上,有一种方法微软可能懒得造假,那就是VerQueryValue读取kernel32.dll等系统文件的产品版本号dwProductVersionMS/LS。有人可能会说,那以后微软不在这里写系统版本了怎么办?实际上,微软已经公开了这个做法,将来不可能大改,否则将有兼容性问题。

XXXXXXXXXXXXXXXXXXXXXXXXXX/en-us/library/windows/desktop/ms724429(v=vs.85).aspx

一般来说,系统文件版本号的格式是XXXXXXXXXXXXXXXXXXXXv。不过,已淘汰的Windows 95/98/Me并不遵守这个约定,它们的系统文件版本号是major.minor.0.build。不过,可以通过dwFileOS是否设置有VOS_DOS位来判断Windows 95/98/Me,而且它们的版本号都是4.x,现在的操作系统版本号早已超过5.0。

不建议读取dwFileVersionMS/LS,它是kernel32.dll文件本身的版本号,而不是系统的版本号。

为了保证可靠,这里也不推荐使用GetFileVersionInfo,因为Windows也可以在这个函数上做手脚。建议直接读取已加载的kernel32.dll模块的资源段,方法如下:

  • GetModuleHandle获取已加载的kernel32.dll模块地址
  • LockResource(LoadResource(h, FindResource(h, n, t)))获取kernel32.dll资源段编号为1的RT_VERSION资源首地址
  • VerQueryValue查询路径为"\\"的版本信息,即VS_FIXEDFILEINFO结构体
  • 将dwProductVersionMS和dwProductVersionLS组合成ULONGLONG,即为正确的系统版本
  • 获得的ULONGLONG版本信息可以作为无符号数直接判断大小
<code class="language-cpp">#include <windows.h>
#include <tchar.h>
#pragma comment(lib, "version.lib")

BOOL CheckModuleProductVersion(LPCTSTR modname, WORD major, WORD minor, WORD build, WORD rev)
{
	HMODULE hmod = GetModuleHandle(modname);
	if (!hmod)
		return FALSE;
	LPVOID verblock = LockResource(LoadResource(hmod, FindResource(hmod, MAKEINTRESOURCE(1), MAKEINTRESOURCE(RT_VERSION))));
	if (!verblock)
		return FALSE;
	VS_FIXEDFILEINFO *pvsffi = NULL;
	UINT szvsffi = 0;
	if (!VerQueryValue(verblock, _T("\\"), (LPVOID*)&pvsffi, &szvsffi))
		return FALSE;
	ULONGLONG ullProductVersion = ((ULONGLONG)pvsffi->dwProductVersionMS << 32) + pvsffi->dwProductVersionLS;
	ULONGLONG ullReqVersion = ((ULONGLONG)major << 48) + ((ULONGLONG)minor << 32) + ((ULONGLONG)build << 16) + rev;
	if (ullProductVersion < ullReqVersion)
		return FALSE;
	return TRUE;
}

BOOL GetOSVersion(PULONGLONG pullProductVersion, PBOOL piswin9x)
{
#pragma comment(lib, "version.lib")
	HMODULE hmod = GetModuleHandle(_T("kernel32.dll"));
	if (!hmod)
		return FALSE;
	LPVOID verblock = LockResource(LoadResource(hmod, FindResource(hmod, MAKEINTRESOURCE(1), MAKEINTRESOURCE(RT_VERSION))));
	if (!verblock)
		return FALSE;
	VS_FIXEDFILEINFO *pvsffi = NULL;
	UINT szvsffi = 0;
	if (!VerQueryValue(verblock, _T("\\"), (LPVOID*)&pvsffi, &szvsffi))
		return FALSE;
	if (pullProductVersion)
		*pullProductVersion = ((ULONGLONG)pvsffi->dwProductVersionMS << 32) + pvsffi->dwProductVersionLS;
	if (piswin9x)
		*piswin9x = !!(pvsffi->dwFileOS & VOS_DOS);
	return TRUE;
}

BOOL Is_Win7_OrGreater()
{
	ULONGLONG osver = 0;
	if (!GetOSVersion(&osver, NULL))
		return FALSE;
	return osver >= (6UI64 << 48) + (1UI64 << 32);
}
</tchar.h></windows.h></code>

[修改于 7年8个月前 - 2017/05/01 02:40:15]

来自:计算机科学 / 软件综合
0
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}