Wie erkennt man die echte Windows-Version?
Frage
Ich weiß, dass ich die GetVersionEx Win32-API-Funktion aufrufen kann, um die Windows-Version abzurufen.In den meisten Fällen spiegelt der zurückgegebene Wert die Version meines Windows wider, aber manchmal ist das nicht der Fall.
Wenn ein Benutzer meine Anwendung unter der Kompatibilitätsschicht ausführt, meldet GetVersionEx nicht die tatsächliche Version, sondern die von der Kompatibilitätsschicht erzwungene Version.Wenn ich beispielsweise Vista verwende und mein Programm im Kompatibilitätsmodus „Windows NT 4“ ausführe, gibt GetVersionEx nicht Version 6.0, sondern 4.0 zurück.
Gibt es eine Möglichkeit, dieses Verhalten zu umgehen und eine echte Windows-Version zu erhalten?
Lösung
Der beste Ansatz, den ich weiß, ist, zu überprüfen, ob bestimmte API von einer DLL exportiert wird. Jede neue Windows-Version fügt neue Funktionen und durch die Existenz dieser Funktionen Überprüfung kann man sagen, welches Betriebssystem die Anwendung läuft. Zum Beispiel exportiert Vista GetLocaleInfoEx von kernel32.dll während früheres Windowses nicht.
die lange Geschichte kurz zu machen, hier ist eine solche Liste nur die Exporte aus kernel32.dll enthält.
> *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
Das Schreiben die Funktion des realen OS-Version ist einfach zu bestimmen; gehen Sie nur vom neuesten OS ältesten und benutzen GetProcAddress exportierten APIs zu überprüfen. Die Umsetzung dieses in jeder Sprache sollte trivial sein.
Der folgende Code in Delphi wurde von dem freien DSiWin32 Bibliothek):
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 }
--- aktualisiert 2009-10-09
Es stellt sich heraus, dass es sehr schwer wird eine „undokumentierte“ OS-Erkennung auf Vista SP1 und höher zu tun. Ein Blick auf die API-Änderungen zeigt, dass alle Windows- 2008-Funktionen werden auch in Vista SP1 und dass alle Windows-7-Funktionen sind auch in Windows 2008 R2 implementiert implementiert. Schade: (
--- Ende update
FWIW, ist dies ein Problem, das ich in der Praxis auftreten. Wir (die Firma für die ich arbeite) haben ein Programm, das nicht wirklich Vista-ready war, als Vista veröffentlicht wurde (und einige Wochen danach ...). Es wurde auch nicht unter der Kompatibilitätsschicht arbeiten. (Einige DirectX Probleme. Fragen Sie nicht.)
Wir haben nicht wollen zu-smart-für-ihre-own-gut-Benutzer diese App auf Vista laufen überhaupt - Kompatibilitätsmodus oder nicht - so hatte ich eine Lösung zu finden (ein Mann und klüger als ich mich darauf in richtige Richtung, oberhalb der Stoff ist nicht meine Idee). Jetzt Posting ich es für Ihr Vergnügen und alle armen Seelen zu helfen, die dieses Problem in Zukunft zu lösen haben. Google, bitte Index diesen Artikel!
Wenn Sie eine bessere Lösung (oder ein Upgrade und / oder reparieren für meine), schreibe eine Antwort hier ...
Andere Tipps
WMI-Abfrage:
"Select * from Win32_OperatingSystem"
EDIT: Eigentlich besser wäre:
"Select Version from Win32_OperatingSystem"
Sie könnten dies in Delphi implementieren etwa so:
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;
Wie wäre es die Version einer Systemdatei zu erhalten?
Die beste Datei wäre kernel32.dll, in% windir% \ system32 \ kernel32.dll.
Es gibt APIs, um die Dateiversion zu erhalten. zB: Ich verwende Windows XP -> "5.1.2600.5512 (xpsp.080413-2111)"
Eine andere Lösung:
Lesen Sie den folgenden Registrierungseintrag:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName
oder andere Tasten aus
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
real Versionsspeicher auf PEB Block von Prozessinformationen.
Beispiel für Win32 app (Delphi-Code)
unit RealWindowsVerUnit;
interface
uses
Windows;
var
//Real version Windows
Win32MajorVersionReal: Integer;
Win32MinorVersionReal: Integer;
implementation
type
PPEB=^PEB;
PEB = record
InheritedAddressSpace: Boolean;
ReadImageFileExecOptions: Boolean;
BeingDebugged: Boolean;
Spare: Boolean;
Mutant: Cardinal;
ImageBaseAddress: Pointer;
LoaderData: Pointer;
ProcessParameters: Pointer; //PRTL_USER_PROCESS_PARAMETERS;
SubSystemData: Pointer;
ProcessHeap: Pointer;
FastPebLock: Pointer;
FastPebLockRoutine: Pointer;
FastPebUnlockRoutine: Pointer;
EnvironmentUpdateCount: Cardinal;
KernelCallbackTable: PPointer;
EventLogSection: Pointer;
EventLog: Pointer;
FreeList: Pointer; //PPEB_FREE_BLOCK;
TlsExpansionCounter: Cardinal;
TlsBitmap: Pointer;
TlsBitmapBits: array[0..1] of Cardinal;
ReadOnlySharedMemoryBase: Pointer;
ReadOnlySharedMemoryHeap: Pointer;
ReadOnlyStaticServerData: PPointer;
AnsiCodePageData: Pointer;
OemCodePageData: Pointer;
UnicodeCaseTableData: Pointer;
NumberOfProcessors: Cardinal;
NtGlobalFlag: Cardinal;
Spare2: array[0..3] of Byte;
CriticalSectionTimeout: LARGE_INTEGER;
HeapSegmentReserve: Cardinal;
HeapSegmentCommit: Cardinal;
HeapDeCommitTotalFreeThreshold: Cardinal;
HeapDeCommitFreeBlockThreshold: Cardinal;
NumberOfHeaps: Cardinal;
MaximumNumberOfHeaps: Cardinal;
ProcessHeaps: Pointer;
GdiSharedHandleTable: Pointer;
ProcessStarterHelper: Pointer;
GdiDCAttributeList: Pointer;
LoaderLock: Pointer;
OSMajorVersion: Cardinal;
OSMinorVersion: Cardinal;
OSBuildNumber: Cardinal;
OSPlatformId: Cardinal;
ImageSubSystem: Cardinal;
ImageSubSystemMajorVersion: Cardinal;
ImageSubSystemMinorVersion: Cardinal;
GdiHandleBuffer: array [0..33] of Cardinal;
PostProcessInitRoutine: Cardinal;
TlsExpansionBitmap: Cardinal;
TlsExpansionBitmapBits: array [0..127] of Byte;
SessionId: Cardinal;
end;
//Get PEB block current win32 process
function GetPDB: PPEB; stdcall;
asm
MOV EAX, DWORD PTR FS:[30h]
end;
initialization
//Detect true windows wersion
Win32MajorVersionReal := GetPDB^.OSMajorVersion;
Win32MinorVersionReal := GetPDB^.OSMinorVersion;
end.
Die folgenden Werke für mich in Windows 10 ohne die Windows 10 GUID aufgelistet in der Anwendung manifestieren:
uses
System.SysUtils, Winapi.Windows;
type
NET_API_STATUS = DWORD;
_SERVER_INFO_101 = record
sv101_platform_id: DWORD;
sv101_name: LPWSTR;
sv101_version_major: DWORD;
sv101_version_minor: DWORD;
sv101_type: DWORD;
sv101_comment: LPWSTR;
end;
SERVER_INFO_101 = _SERVER_INFO_101;
PSERVER_INFO_101 = ^SERVER_INFO_101;
LPSERVER_INFO_101 = PSERVER_INFO_101;
const
MAJOR_VERSION_MASK = $0F;
function NetServerGetInfo(servername: LPWSTR; level: DWORD; var bufptr): NET_API_STATUS; stdcall; external 'Netapi32.dll';
function NetApiBufferFree(Buffer: LPVOID): NET_API_STATUS; stdcall; external 'Netapi32.dll';
type
pfnRtlGetVersion = function(var RTL_OSVERSIONINFOEXW): LONG; stdcall;
var
Buffer: PSERVER_INFO_101;
ver: RTL_OSVERSIONINFOEXW;
RtlGetVersion: pfnRtlGetVersion;
begin
Buffer := nil;
// Win32MajorVersion and Win32MinorVersion are populated from GetVersionEx()...
ShowMessage(Format('GetVersionEx: %d.%d', [Win32MajorVersion, Win32MinorVersion])); // shows 6.2, as expected per GetVersionEx() documentation
@RtlGetVersion := GetProcAddress(GetModuleHandle('ntdll.dll'), 'RtlGetVersion');
if Assigned(RtlGetVersion) then
begin
ZeroMemory(@ver, SizeOf(ver));
ver.dwOSVersionInfoSize := SizeOf(ver);
if RtlGetVersion(ver) = 0 then
ShowMessage(Format('RtlGetVersion: %d.%d', [ver.dwMajorVersion, ver.dwMinorVersion])); // shows 10.0
end;
if NetServerGetInfo(nil, 101, Buffer) = NO_ERROR then
try
ShowMessage(Format('NetServerGetInfo: %d.%d', [Buffer.sv101_version_major and MAJOR_VERSION_MASK, Buffer.sv101_version_minor])); // shows 10.0
finally
NetApiBufferFree(Buffer);
end;
end.
Aktualisieren :. NetWkstaGetInfo()
würde wahrscheinlich auch funktionieren, ähnlich wie ‚NetServerGetInfo ()`, aber ich habe nicht versuchen, es noch
Hinweis: Gabr fragt nach einem Ansatz, der die Grenzen des GetVersionEx
umgehen kann. JCL-Code verwendet GetVersionEx und unterliegt damit Kompatibilitätsschicht. Diese Information ist für Leute, die brauchen nicht die Kompatibilitätsschicht zu umgehen, nur.
, um den Jedi JCL verwenden, können Sie Einheit JclSysInfo, hinzufügen und Funktion GetWindowsVersion
nennen. Es gibt einen Aufzählungstyp TWindowsVersion.
Zur Zeit JCL enthält alle Windows-Versionen ausgeliefert, und jedes Mal Microsoft liefert eine neue Version von Windows in einer Box geändert wird:
TWindowsVersion =
(wvUnknown, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME,
wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4, wvWin2000, wvWinXP,
wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinServer2008,
wvWin7, wvWinServer2008R2);
Wenn Sie wissen möchten, wenn Sie 64-Bit-Windows-7 anstelle von 32-bit, dann JclSysInfo.IsWindows64
nennen.
Beachten Sie, dass JCL allso Editions Griffe, wie Pro, Ultimate etc. Für diesen Anruf GetWindowsEdition, und es gibt eine davon:
TWindowsEdition =
(weUnknown, weWinXPHome, weWinXPPro, weWinXPHomeN, weWinXPProN, weWinXPHomeK,
weWinXPProK, weWinXPHomeKN, weWinXPProKN, weWinXPStarter, weWinXPMediaCenter,
weWinXPTablet, weWinVistaStarter, weWinVistaHomeBasic, weWinVistaHomeBasicN,
weWinVistaHomePremium, weWinVistaBusiness, weWinVistaBusinessN,
weWinVistaEnterprise, weWinVistaUltimate, weWin7Starter, weWin7HomeBasic,
weWin7HomePremium, weWin7Professional, weWin7Enterprise, weWin7Ultimate);
Für historisches Interesse können Sie die NT-Edition überprüfen auch mit der NtProductType Funktion, gibt sie:
TNtProductType = (ptUnknown, ptWorkStation, ptServer, ptAdvancedServer,
ptPersonal, ptProfessional, ptDatacenterServer,
ptEnterprise, ptWebEdition);
Beachten Sie, dass „N Ausgaben“ oben festgestellt werden. Das ist eine EU (Europe) Version von Windows, erstellt aufgrund der EU-Kartellvorschriften. Das ist eine ziemlich feine Abstufung der Erfassung in der JCL.
Hier ist eine Beispielfunktion, die Sie Vista erkennen helfen, und tun etwas Besonderes, wenn sie auf Vista.
function IsSupported:Boolean;
begin
case GetWindowsVersion of
wvVista: result := false;
else
result := true;
end;
end;
Beachten Sie, wenn Sie wollen, „größer als“ Überprüfung, dann sollten Sie nur andere Techniken verwenden. Beachten Sie auch, dass die Versionsprüfung oft eine Quelle der Zukunft Bruch sein kann. Ich habe in die Regel Benutzer ausgewählt warnen und weiter, so dass mein Binärcode nicht die eigentliche Quelle des Bruches in der Zukunft werden wird.
Vor kurzem habe ich versucht, eine App zu installieren, und das Installer meines Laufwerk freien Speicherplatz überprüft, und würde nicht installieren, weil ich mehr als 2 Gigabyte freien Speicherplatz hatte. Der 32-Bit-Integer-Wert mit Vorzeichen im Installer wurde negativ, brach das Installationsprogramm. Ich hatte es in einer VM zu installieren, um es an die Arbeit. Hinzufügen von „smart-Code“ macht oft die App „dümmer“. Seien Sie vorsichtig.
Im übrigen fand ich, dass aus der Befehlszeile Du Wmic.exe ausführen kannst, und gibt path Win32_OperatingSystem
(Die „Select * von Win32_OperatingSystem“ nicht für mich arbeiten). In Zukunft könnte vielleicht JCL erweitert werden, um die WMI-Informationen zu verwenden.
Im Wesentlichen doppelten Q zu beantworten: Erste OS Dur, Moll und bauen Versionen für Windows 8.1 und bis in Delphi 2007
mit W2K starten können Sie NetServerGetInfo . NetServerGetInfo liefert die richtigen Informationen auf W7 und W8.1, nicht in der Lage auf prüfen W10 ..
function GetWinVersion: string;
var
Buffer: PServerInfo101;
begin
Buffer := nil;
if NetServerGetInfo(nil, 101, Pointer(Buffer)) = NO_ERROR then
try
Result := <Build You Version String here>(
Buffer.sv101_version_major,
Buffer.sv101_version_minor,
VER_PLATFORM_WIN32_NT // Save since minimum support begins in W2K
);
finally
NetApiBufferFree(Buffer);
end;
end;
Eine Anmerkung über NetServerGetInfo mit (), die funktioniert immer noch unter Windows 10 (10240.th1_st1) ...
https: // msdn.microsoft.com/en-us/library/windows/desktop/aa370903%28v=vs.85%29.aspx
sv101_version_major
Die Hauptversionsnummer und der Servertyp.
Die Hauptversion Versionsnummer des Betriebssystems angegeben in den am wenigsten signifikanten 4 Bits. Der Servertyp wird in der angegebenen höchstwertigen 4 Bits. Die MAJOR_VERSION_MASK Bitmaske in der definierte Lmserver.h Header {0x0F} sollte von einer Anwendung verwendet werden, um zu erhalten die Hauptversionsnummer von diesem Mitglied.
Mit anderen Worten (sv101_version_major & MAJOR_VERSION_MASK).