文号
833339
阅读
5655
回复
0
收藏
1
获取Windows版本的可靠方法:VerQueryValue
2017/04/22
IP:四川

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

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

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

一般来说,系统文件版本号的格式是major.minor.build.rev。不过,已淘汰的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版本信息可以作为无符号数直接判断大小
#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>
[ 修改于9年7个月前 - 2017/05/01 02:40:15 ]
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的