Come rilevare la vera versione di Windows?
Domanda
So che posso chiamare il GetVersionEx funzione API Win32 per recuperare la versione di Windows.Nella maggior parte dei casi, viene restituito il valore riflette la versione di Windows, ma a volte non è così.
Se un utente esegue la mia domanda sotto il livello di compatibilità, quindi GetVersionEx non essere segnalato la versione reale, ma la versione imposto dal livello di compatibilità.Per esempio, se io sono in esecuzione Vista ed eseguire il mio programma "Windows NT 4" modalità di compatibilità, GetVersionEx non ritorno versione 6.0 ma la versione 4.0.
C'è un modo per aggirare questo comportamento e ottenere la vera versione di Windows?
Soluzione
L'approccio migliore che conosco è quello di verificare se la specifica API esportato da alcune DLL.Ogni nuova versione di Windows aggiunge nuove funzioni e verificando l'esistenza di tali funzioni si può dire che OS l'applicazione è in esecuzione.Per esempio, Vista esportazioni GetLocaleInfoEx da kernel32.dll mentre le precedenti Windowses non.
Per tagliare la lunga storia breve, qui è una lista contenente solo le esportazioni dal 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
Scrivere la funzione di determinare la vera versione del sistema operativo è semplice;basta procedere dal sistema operativo più recente al più vecchio e utilizzare GetProcAddress per verificare esportato Api.L'implementazione di questo in qualsiasi lingua dovrebbe essere banale.
Il codice riportato di seguito in Delphi è stato estratto gratuito DSiWin32 libreria:
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 }
--- aggiornato 2009-10-09
Si scopre che diventa molto difficile fare un "senza documenti" OS detection su Vista SP1 e versioni successive.Uno sguardo al Modifiche alle API mostra che tutte le Finestre 2008 funzioni sono state implementate anche in Vista SP1 e Windows 7 funzioni sono implementate in Windows 2008 R2.Troppo male :(
--- end di aggiornamento
FWIW, questo è un problema che ho incontrato nella pratica.Noi (l'azienda per cui lavoro) dispone di un programma che non era davvero pronto per Vista quando Vista è stato rilasciato (e alcune settimane dopo di che ...).Non stava lavorando sotto il livello di compatibilità sia.(Alcuni problemi con DirectX.Non chiedere.)
Non volevamo troppo-smart-per-loro-proprio-buona agli utenti di eseguire questa applicazione su Vista - la modalità di compatibilità o non - così ho dovuto trovare una soluzione (un ragazzo più intelligente di me mi hanno indirizzato nella giusta direzione;la roba di cui sopra non è una mia invenzione).Ora sto postando per il vostro piacere e per aiutare tutte le povere anime che dovrà risolvere questo problema in futuro.Google, si prega di indice di questo articolo!
Se avete una soluzione migliore (o un aggiornamento e/o di correzione per la mia), si prega di inviare una risposta qui ...
Altri suggerimenti
WMI QUery:
"Select * from Win32_OperatingSystem"
EDIT:In realtà sarebbe meglio:
"Select Version from Win32_OperatingSystem"
Si potrebbe implementare questo in Delphi in questo modo:
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;
Come su come ottenere la versione di un file di sistema?
Il file migliore sarebbe kernel32.dll situato in %WINDIR%\System32\kernel32.dll.
Ci sono le Api per ottenere la versione del file.ad esempio:Sto utilizzando Windows XP -> "5.1.2600.5512 (xpsp.080413-2111)"
Un'altra soluzione:
leggi la seguente voce del registro di sistema:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName
o altri tasti da
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
versione reale archivio PEB blocco di informazioni di processo.
Esempio di applicazione di Win32 (Delphi Codice)
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.
Le seguenti opere per me in Windows 10 senza Windows 10 GUID elencate nel manifesto dell'applicazione:
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.
Aggiornamento: NetWkstaGetInfo()
probabilmente anche il lavoro, simile a 'NetServerGetInfo()`, ma non ho prova di sicurezza.
Nota: Gabr chiede su un approccio che può bypassare le limitazioni di GetVersionEx
.JCL codice utilizza GetVersionEx, ed è quindi soggetto a livello di compatibilità.Questa informazione è per le persone che non hanno bisogno di ignorare il livello di compatibilità, solo.
Utilizzando il Jedi JCL, è possibile aggiungere unità JclSysInfo, e la funzione di chiamata GetWindowsVersion
.Restituisce un tipo enumerato TWindowsVersion.
Attualmente JCL contiene tutti spediti versioni di windows, e viene cambiato ogni volta che Microsoft disponibile una nuova versione di Windows in una scatola:
TWindowsVersion =
(wvUnknown, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME,
wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4, wvWin2000, wvWinXP,
wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinServer2008,
wvWin7, wvWinServer2008R2);
Se vuoi sapere se sei in esecuzione a 64 bit di windows 7 invece di 32 bit, quindi chiamare JclSysInfo.IsWindows64
.
Nota che JCL allso maniglie Edizioni, come Pro, Ultimate, etc.Per tale chiamata GetWindowsEdition, e restituisce uno di questi:
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);
Per interesse storico, è possibile controllare il NT a livello di edizione con la NtProductType funzione, restituisce:
TNtProductType = (ptUnknown, ptWorkStation, ptServer, ptAdvancedServer,
ptPersonal, ptProfessional, ptDatacenterServer,
ptEnterprise, ptWebEdition);
Nota che "N edizioni" sono rilevati in precedenza.Che la UE (Europa) versione di Windows, creato a causa di UE le regole antitrust.Che bella la fine gradazione di rilevamento all'interno del JCL.
Ecco un esempio di una funzione che consente di rilevare Vista, e fare qualcosa di speciale quando su Vista.
function IsSupported:Boolean;
begin
case GetWindowsVersion of
wvVista: result := false;
else
result := true;
end;
end;
Nota che se vuoi fare "maggiore di" controllo, allora si dovrebbe usare altre tecniche.Inoltre, si noti che la versione di controllo può spesso essere fonte di future rotture.Solitamente ho scelto di avvisare gli utenti e continuare, in modo che il mio codice binario non diventi la fonte reale di rottura in futuro.
Di recente ho provato ad installare un app, e il programma di installazione controllato il mio spazio libero su disco, e non installare, perché ho avuto più di 2 gigabyte di spazio libero.Il numero intero a 32 bit firmato valore in il programma di installazione è diventato negativo, rompendo il programma di installazione.Ho dovuto installarlo in una macchina virtuale per farlo funzionare.L'aggiunta di "codice smart", spesso rende l'app "stupidi".Essere cauti.
Per inciso, ho scoperto che da riga di comando, è possibile eseguire WMIC.exe e tipo di path Win32_OperatingSystem
("Select * from Win32_OperatingSystem" non ha funzionato per me).In futuro, forse, JCL potrebbe essere estesa ad utilizzare le informazioni di WMI.
Essenzialmente per rispondere a duplicare D: Ottenere OS (maggiore, minore, e costruire le versioni per Windows 8.1 e in Delphi 2007
Partenza con W2K è possibile utilizzare NetServerGetInfo.NetServerGetInfo restituisce le informazioni corrette su W7 e W8.1, in grado di testare su 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;
Una nota sull'utilizzo di NetServerGetInfo(), che funziona ancora su Windows 10 (10240.th1_st1)...
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370903%28v=vs.85%29.aspx
sv101_version_major
Il numero di versione principale e il tipo di server.
La major release numero di versione del sistema operativo è specificato in meno significativo di 4 bit.Il tipo di server è specificato nel più significativi di 4 bit.Il MAJOR_VERSION_MASK maschera di bit definito nel Lmserver.h header {0x0F} deve essere utilizzato da un'applicazione per ottenere il numero di versione principale di questo membro.
In altre parole, (sv101_version_major & MAJOR_VERSION_MASK).