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?

War es hilfreich?

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).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top