如何检测真实的Windows版本?
我知道我可以调用GetVersionEx Win32 API函数来检索Windows版本。在大多数情况下,返回的值反映了我的Windows版本,但有时并非如此。
如果用户在兼容性层下运行我的应用程序,则GetVersionEx不会报告真实版本,而是报告由兼容性层强制执行的版本。例如,如果我运行Vista并以" Windows NT 4"兼容模式执行程序,则GetVersionEx不会返回版本6.0,而是4.0。
有没有一种方法可以绕过此行为并获得真实的Windows版本?
解决方案
回答
WMI查询:
"Select * from Win32_OperatingSystem"
编辑:实际上更好是:
"Select Version from Win32_OperatingSystem"
我们可以这样在Delphi中实现:
function OperatingSystemDisplayName: string; function GetWMIObject(const objectName: string): IDispatch; var chEaten: Integer; BindCtx: IBindCtx; Moniker: IMoniker; begin OleCheck(CreateBindCtx(0, bindCtx)); OleCheck(MkParseDisplayName(BindCtx, PChar(objectName), chEaten, Moniker)); OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result)); end; function VarToString(const Value: OleVariant): string; begin if VarIsStr(Value) then begin Result := Trim(Value); end else begin Result := ''; end; end; function FullVersionString(const Item: OleVariant): string; var Caption, ServicePack, Version, Architecture: string; begin Caption := VarToString(Item.Caption); ServicePack := VarToString(Item.CSDVersion); Version := VarToString(Item.Version); Architecture := ArchitectureDisplayName(SystemArchitecture); Result := Caption; if ServicePack <> '' then begin Result := Result + ' ' + ServicePack; end; Result := Result + ', version ' + Version + ', ' + Architecture; end; var objWMIService: OleVariant; colItems: OleVariant; Item: OleVariant; oEnum: IEnumvariant; iValue: LongWord; begin Try objWMIService := GetWMIObject('winmgmts:\localhost\root\cimv2'); colItems := objWMIService.ExecQuery('SELECT Caption, CSDVersion, Version FROM Win32_OperatingSystem', 'WQL', 0); oEnum := IUnknown(colItems._NewEnum) as IEnumVariant; if oEnum.Next(1, Item, iValue)=0 then begin Result := FullVersionString(Item); exit; end; Except // yes, I know this is nasty, but come what may I want to use the fallback code below should the WMI code fail End; (* Fallback, relies on the deprecated function GetVersionEx, reports erroneous values when manifest does not contain supportedOS matching the executing system *) Result := TOSVersion.ToString; end;
回答
我知道的最好方法是检查特定的API是否从某些DLL中导出。 Windows的每个新版本都添加了新功能,并且通过检查这些功能的存在,可以知道应用程序在哪个OS上运行。例如,Vista从kernel32.dll导出GetLocaleInfoEx,而以前的Windows没有。
长话短说,这是一个仅包含kernel32.dll导出的列表。
> *function: implemented in* > GetLocaleInfoEx: Vista > GetLargePageMinimum: Vista, Server 2003 GetDLLDirectory: Vista, Server 2003, XP SP1 GetNativeSystemInfo: Vista, Server 2003, XP SP1, XP ReplaceFile: Vista, Server 2003, XP SP1, XP, 2000 OpenThread: Vista, Server 2003, XP SP1, XP, 2000, ME GetThreadPriorityBoost: Vista, Server 2003, XP SP1, XP, 2000, NT 4 IsDebuggerPresent: Vista, Server 2003, XP SP1, XP, 2000, ME, NT 4, 98 GetDiskFreeSpaceEx: Vista, Server 2003, XP SP1, XP, 2000, ME, NT 4, 98, 95 OSR2 ConnectNamedPipe: Vista, Server 2003, XP SP1, XP, 2000, NT 4, NT 3 Beep: Vista, Server 2003, XP SP1, XP, 2000, ME, 98, 95 OSR2, 95
编写确定实际OS版本的函数很简单;只需从最新的操作系统升级到最旧的操作系统,然后使用GetProcAddress检查导出的API。用任何一种语言来实现这一点都是微不足道的。
以下Delphi中的代码是从免费的DSiWin32库中提取的):
TDSiWindowsVersion = (wvUnknown, wvWin31, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME, wvWin9x, wvWinNT3, wvWinNT4, wvWin2000, wvWinXP, wvWinNT, wvWinServer2003, wvWinVista); function DSiGetWindowsVersion: TDSiWindowsVersion; var versionInfo: TOSVersionInfo; begin versionInfo.dwOSVersionInfoSize := SizeOf(versionInfo); GetVersionEx(versionInfo); Result := wvUnknown; case versionInfo.dwPlatformID of VER_PLATFORM_WIN32s: Result := wvWin31; VER_PLATFORM_WIN32_WINDOWS: case versionInfo.dwMinorVersion of 0: if Trim(versionInfo.szCSDVersion[1]) = 'B' then Result := wvWin95OSR2 else Result := wvWin95; 10: if Trim(versionInfo.szCSDVersion[1]) = 'A' then Result := wvWin98SE else Result := wvWin98; 90: if (versionInfo.dwBuildNumber = 73010104) then Result := wvWinME; else Result := wvWin9x; end; //case versionInfo.dwMinorVersion VER_PLATFORM_WIN32_NT: case versionInfo.dwMajorVersion of 3: Result := wvWinNT3; 4: Result := wvWinNT4; 5: case versionInfo.dwMinorVersion of 0: Result := wvWin2000; 1: Result := wvWinXP; 2: Result := wvWinServer2003; else Result := wvWinNT end; //case versionInfo.dwMinorVersion 6: Result := wvWinVista; end; //case versionInfo.dwMajorVersion end; //versionInfo.dwPlatformID end; { DSiGetWindowsVersion } function DSiGetTrueWindowsVersion: TDSiWindowsVersion; function ExportsAPI(module: HMODULE; const apiName: string): boolean; begin Result := GetProcAddress(module, PChar(apiName)) <> nil; end; { ExportsAPI } var hKernel32: HMODULE; begin { DSiGetTrueWindowsVersion } hKernel32 := GetModuleHandle('kernel32'); Win32Check(hKernel32 <> 0); if ExportsAPI(hKernel32, 'GetLocaleInfoEx') then Result := wvWinVista else if ExportsAPI(hKernel32, 'GetLargePageMinimum') then Result := wvWinServer2003 else if ExportsAPI(hKernel32, 'GetNativeSystemInfo') then Result := wvWinXP else if ExportsAPI(hKernel32, 'ReplaceFile') then Result := wvWin2000 else if ExportsAPI(hKernel32, 'OpenThread') then Result := wvWinME else if ExportsAPI(hKernel32, 'GetThreadPriorityBoost') then Result := wvWinNT4 else if ExportsAPI(hKernel32, 'IsDebuggerPresent') then //is also in NT4! Result := wvWin98 else if ExportsAPI(hKernel32, 'GetDiskFreeSpaceEx') then //is also in NT4! Result := wvWin95OSR2 else if ExportsAPI(hKernel32, 'ConnectNamedPipe') then Result := wvWinNT3 else if ExportsAPI(hKernel32, 'Beep') then Result := wvWin95 else // we have no idea Result := DSiGetWindowsVersion; end; { DSiGetTrueWindowsVersion }
-更新2009-10-09
事实证明,在Vista SP1及更高版本上进行"未记录"的操作系统检测非常困难。查看API更改,可以发现Vista SP1中也实现了所有Windows 2008功能,而Windows 2008 R2中也实现了所有Windows 7功能。太糟糕了 :(
-更新结束
FWIW,这是我在实践中遇到的问题。我们(我工作的公司)所拥有的程序在Vista发行时(以及此后的数周……)还不是真正适用于Vista的程序。它也不在兼容层下工作。 (一些DirectX问题。不要问。)
我们不希望自己聪明的用户在所有兼容模式下都在Vista上运行此应用程序,所以我不得不寻找解决方案(比我聪明的人向我指出了正确的方向;这些东西以上不是我的想法)。现在,我将其发布为我们带来乐趣,并帮助所有将来需要解决此问题的可怜人。 Google,请为本文编索引!
如果我们有更好的解决方案(或者针对我的升级和/或者修复),请在此处发布答案...
回答
如何获取系统文件的版本?
最好的文件是kernel32.dll,位于%WINDIR%\ System32 \ kernel32.dll中。
有用于获取文件版本的API。例如:我正在使用Windows XP->" 5.1.2600.5512(xpsp.080413-2111)"
回答
另一个解决方案:
阅读以下注册表项:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName
或者其他键
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion