Wersja systemu Windows

mgyver

Jak wiadomo Microsoft wypuszcza coraz to nowsze wersje systemu Windows. Istnieje więc potrzeba rozpoznawania nowszych wersji tego systemu, ale kod w delphi potrzebny do tego najczęściej pozostaje stary i nieaktualny. Proponuję wiec skorzystanie z poniższego modułu który na stan obecny rozpoznaje wersje Windows do Windows Seven włącznie. Zapraszam również do aktualizacji kodu tego arta w przyszłości.

Moduł OS_Version:

unit OS_Version;

interface

uses Windows, Registry, SysUtils;

type
  TWindowsType = (winUnknown, win31, win95, win95OSR2, winNT, win98, win98se, winME, win2000, winXP,
                  winXPx64, win2003, win2003R2, winVista, winServer2008, winServer2008R2, winSeven);

  TWindowsProductType = ( wptWorkstation, wptServer );

  TWindowsProductKind = record
    AsString    : String;
    AsType      : TWindowsProductType;
  end; 

  TWindowsProductVersion = record 
    AsString    : String; 
    Major       : Integer; 
    Minor       : Integer; 
  end; 

  TWindowsTypeEx = record
    Full        : String; 
    Product     : String; 
    Kind        : TWindowsProductKind;
    OSKind      : TWindowsType;
    OSVersion   : TWindowsProductVersion;
    Server      : Boolean;
    OSBuild     : Integer;
    ServicePack : String;
    ServicePackVersion : TWindowsProductVersion;
  end;

function GetWindowsOS: TWindowsTypeEx;

implementation

function IsBitSet(const val: Longint; const TheBit: Byte): Boolean;
begin
  Result := (val and (1 shl TheBit)) <> 0;
end;

function GetWindowsOS: TWindowsTypeEx;
const
  VER_NT_WORKSTATION                 : integer = $1;
  VER_NT_DOMAIN_CONTROLLER           : integer = $2;         // The system is a domain controller. 
  VER_NT_SERVER                      : integer = $3;         // The system is a server. 
  VER_WORKSTATION_NT                 : integer = $40000000; 

  SM_SERVERR2                        : integer = 89; 

  VER_SUITE_SMALLBUSINESS            : integer = 0;        // Bit 0 { int 1 } = Microsoft Small Business Server was once installed on the system, 
                                                           //                   but may have been upgraded to another version of Windows. 

  VER_SUITE_SMALLBUSINESS_RESTRICTED : integer = 5;        // Bit 5 { int 32 } = Microsoft Small Business Server is installed with the restrictive client license in force.

  VER_SUITE_ENTERPRISE               : integer = 1;        // Bit 1 { int 2 } = Windows Server "Longhorn", Enterprise Edition, 
                                                           //                   Windows Server 2003, Enterprise Edition, 
                                                           //                   Windows 2000 Advanced Server, 
                                                           //                   Windows NT Server 4.0 Enterprise Edition is installed. 
                                                           // Refer to the Remarks section for more information about this bit flag. 

  VER_SUITE_BACKOFFICE               : integer = 2;        // Bit 2 { int 4 } = Microsoft BackOffice components are installed. 
  VER_SUITE_COMMUNICATIONS           : integer = 3;        // Bit 3 { int 8 } 
  VER_SUITE_TERMINAL                 : integer = 4;        // Bit 4 { int 16 } = Terminal Services is installed. 

                                                           // Refer to the Remarks section for more information about this bit flag. 
  VER_SUITE_EMBEDDEDNT               : integer = 6;        // Bit 6 { int 64 } = Windows XP Embedded is installed. 
  VER_SUITE_DATACENTER               : integer = 7;        // Bit 7 { int 128 } = Windows Server "Longhorn", Datacenter Edition
                                                           //                     Windows Server 2003, Datacenter Edition 
                                                           //                     Windows 2000 Datacenter Server is installed. 
  VER_SUITE_SINGLEUSERTS             : integer = 8;        // Bit 8 { int 256 } = Terminal server in remote admin mode 
  VER_SUITE_PERSONAL                 : integer = 9;        // Bit 9 { int 512 } = Windows XP Home Edition is installed.
  VER_SUITE_BLADE                    : integer = 10;       // Bit 10 { int 1024 } = Windows Server 2003, Web Edition is installed. 
  VER_SUITE_COMPUTE_SERVER           : integer = 14;       // Bit 14 { int 16384 } = Windows Server 2003, Compute Cluster Edition is installed. 
  VER_SUITE_STORAGE_SERVER           : integer = 13;       // Bit 13 { int 8192 } = Windows Storage Server 2003 R2 is installed. 


  PROCESSOR_ARCHITECTURE_AMD64         : integer = 9;     // x64 (AMD or Intel) 
  PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 : integer = 10;    // WOW64 
  PROCESSOR_ARCHITECTURE_IA64          : integer = 6;     // Intel Itanium Processor Family (IPF)
  PROCESSOR_ARCHITECTURE_INTEL         : integer = 0;     // x86
  PROCESSOR_ARCHITECTURE_UNKNOWN       : integer = $ffff; 

type 
  OSVERSIONINFOEX = packed record 
    dwOSVersionInfoSize: DWORD; 
    dwMajorVersion: DWORD;
    dwMinorVersion: DWORD; 
    dwBuildNumber: DWORD; 
    dwPlatformId: DWORD; 
    szCSDVersion: Array [0..127] of Char;
    wServicePackMajor: WORD; 
    wServicePackMinor: WORD; 
    wSuiteMask: WORD; 
    wProductType: BYTE; 
    wReserved: BYTE; 
  End; 
  TOSVersionInfoEx = OSVERSIONINFOEX; 
  POSVersionInfoEx = ^TOSVersionInfoEx; 

  PSystemInfo = ^System_Info; 

  TSIProc = procedure( SI : PSystemInfo ); stdcall;
  PSIProc = TSIProc;

var OSVI : TOSVersionInfoEx;
    OS   : TOSVersionInfo;
    IsOSVIEx : boolean;
    SI : SYSTEM_INFO;
    pSI : PSIProc;
    pVer : POSVersionInfo;  // old version!
    r : TRegistry;
    ts : string;
begin
  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
  // If that fails, try using the OSVERSIONINFO structure.
  ZeroMemory(@OSVI,SizeOf(OSVI));
  osvi.dwOSVersionInfoSize := sizeof(OSVI);

  pVer := @OSVI;

  IsOSVIEx := GetVersionEx ( pVer^ );

  if not IsOSVIEx then
    begin
      osvi.dwOSVersionInfoSize := sizeof(OS); 
      if not GetVersionEx ( pVer^ ) then 
        exit;
    end;

  Result.OSVersion.AsString := Format('%d.%d',[OSVI.dwMajorVersion,OSVI.dwMinorVersion]);
  Result.OSVersion.Major    := OSVI.dwMajorVersion; 
  Result.OSVersion.Minor    := OSVI.dwMinorVersion;

  Result.ServicePackVersion.AsString := format('%d.%d',[OSVI.wServicePackMajor,OSVI.wServicePackMinor]);
  Result.ServicePackVersion.Major    := OSVI.wServicePackMajor;
  Result.ServicePackVersion.Minor    := OSVI.wServicePackMinor; 

  Result.Server := False;

  Result.OSBuild := OSVI.dwBuildNumber; 

  case OSVI.dwPlatformId of 

    // Test for the Windows NT product family. 
    VER_PLATFORM_WIN32_NT: 

      begin 

        // Test for the specific product family.
        if ( osvi.dwMajorVersion = 6 ) and ( osvi.dwMinorVersion = 1 ) then
          begin
            if( osvi.wProductType = VER_NT_WORKSTATION ) then
              begin
                Result.Product := 'Microsoft Windows Seven';
                Result.OSKind := winSeven;
              end
            else
              begin
                Result.Product := 'Microsoft Windows Server 2008 R2';
                Result.OSKind := winServer2008R2;
              end;
          end;

        if ( osvi.dwMajorVersion = 6 ) and ( osvi.dwMinorVersion = 0 ) then
          begin
            if( osvi.wProductType = VER_NT_WORKSTATION ) then
              begin
                Result.Product := 'Microsoft Windows Vista';
                Result.OSKind := winVista;
              end
            else
              begin
                Result.Product := 'Microsoft Windows Server 2008';
                Result.OSKind := winServer2008;
              end;
          end;

        if ( osvi.dwMajorVersion = 5 ) and ( osvi.dwMinorVersion = 2 ) then 
          begin 

            // Use GetProcAddress to avoid load issues on Windows 2000 
             
            pSI := GetProcAddress( GetModuleHandle('kernel32.dll'), 'GetNativeSystemInfo'); 
            try 
              pSI(@SI);
            except 
            end; 

            if ( GetSystemMetrics( SM_SERVERR2 ) <> 0 ) then 
              begin 
                Result.Product := 'Microsoft Windows Server 2003 R2'; 
                Result.OSKind := win2003R2;
              end
            else if ( osvi.wProductType = VER_NT_WORKSTATION ) and 
                    ( SI.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64 ) then 
              begin 
                Result.Product := 'Microsoft Windows XP Professional x64 Edition'; 
                Result.OSKind := winXPx64; 
              end 
            else 
              begin
                Result.Product := 'Microsoft Windows Server 2003 family'; 
                Result.OSKind  := win2003; 
              end; 
          end; 

        if ( osvi.dwMajorVersion = 5 ) and ( osvi.dwMinorVersion = 1 ) then 
          begin 
            Result.Product := 'Microsoft Windows XP';
            Result.OSKind  := winXP; 
          end; 

        if ( osvi.dwMajorVersion = 5 ) and ( osvi.dwMinorVersion = 0 ) then 
          begin 
            Result.Product := 'Microsoft Windows 2000'; 
            Result.OSKind  := win2000; 
          end;

        if ( osvi.dwMajorVersion <= 4 ) then 
          begin 
            Result.Product := 'Microsoft Windows NT'; 
            Result.OSKind  := winNT; 
          end; 


        // Test for specific product on Windows NT 4.0 SP6 and later. 
        if( IsOSVIEx ) then 
          begin 

            if ( osvi.wProductType = VER_NT_WORKSTATION ) and 
               ( si.wProcessorArchitecture <> PROCESSOR_ARCHITECTURE_AMD64) then 
              begin 

                Result.Kind.AsType := wptWorkstation;

                if( osvi.dwMajorVersion = 4 ) then 
                  Result.Kind.AsString := 'Workstation 4.0' 
                else if IsBitSet(osvi.wSuiteMask, VER_SUITE_PERSONAL ) then
                  Result.Kind.AsString := 'Home Edition'
                else 
                  Result.Kind.AsString := 'Professional'; 
              end 

            // Test for the server type.
            else if ( osvi.wProductType = VER_NT_SERVER ) or 
                    ( osvi.wProductType = VER_NT_DOMAIN_CONTROLLER ) then 
              begin 

                Result.Server := True;
                Result.Kind.AsType := wptServer; 

                // 2003 Server family 
                if ( osvi.dwMajorVersion = 5 ) and ( osvi.dwMinorVersion = 2 ) then 
                  begin

                    if ( si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64 ) then 
                      begin 
                        if IsBitSet(osvi.wSuiteMask, VER_SUITE_DATACENTER ) then 
                          Result.Kind.AsString := 'Datacenter Edition for Itanium-based Systems' 
                        else if IsBitSet(osvi.wSuiteMask, VER_SUITE_ENTERPRISE ) then 
                          Result.Kind.AsString := 'Enterprise Edition for Itanium-based Systems'; 
                      end 
                    else if ( si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64 ) then 
                      begin 
                        if IsBitSet(osvi.wSuiteMask, VER_SUITE_DATACENTER ) then 
                          Result.Kind.AsString := 'Datacenter x64 Edition'
                        else if IsBitSet(osvi.wSuiteMask, VER_SUITE_ENTERPRISE ) then 
                          Result.Kind.AsString := 'Enterprise x64 Edition' 
                        else 
                          Result.Kind.AsString := 'Standard x64 Edition'

                      end 
                    else 
                      begin 
                        if IsBitSet(osvi.wSuiteMask, VER_SUITE_DATACENTER ) then 
                          Result.Kind.AsString := 'Datacenter Edition' 
                        else if IsBitSet(osvi.wSuiteMask, VER_SUITE_ENTERPRISE ) then
                          Result.Kind.AsString := 'Enterprise Edition' 
                        else if IsBitSet(osvi.wSuiteMask, VER_SUITE_BLADE ) then 
                          Result.Kind.AsString := 'Web Edition' 
                        else if IsBitSet(osvi.wSuiteMask, VER_SUITE_SMALLBUSINESS ) then 
                          Result.Kind.AsString := 'Small Business Server' 
                        else if IsBitSet(osvi.wSuiteMask, VER_SUITE_SMALLBUSINESS_RESTRICTED ) then 
                          Result.Kind.AsString := 'Small Business Server ( Restricted )' 
                        else 
                          Result.Kind.AsString := 'Standard Edition' 
                      end; 

                  end 

                // 2000 Server family 
                else if ( osvi.dwMajorVersion = 5 ) and ( osvi.dwMinorVersion = 0 ) then 
                  begin 
                    Result.Product := 'Microsoft Windows Server 2000 family'; 

                    if IsBitSet(osvi.wSuiteMask, VER_SUITE_DATACENTER ) then
                      Result.Kind.AsString := 'Datacenter Server' 
                    else if IsBitSet(osvi.wSuiteMask, VER_SUITE_ENTERPRISE ) then 
                      Result.Kind.AsString := 'Advanced Server'
                    else 
                      Result.Kind.AsString := 'Server'; 
                  end 

                // Windows NT 4.0 
                else 
                  begin 
                    if IsBitSet(osvi.wSuiteMask, VER_SUITE_ENTERPRISE ) then 
                      Result.Kind.AsString := 'Server 4.0 Enterprise Edition' 
                    else
                      Result.Kind.AsString := 'Server 4.0'; 
                  end; 
              end; 
          end

        // Test for specific product on Windows NT 4.0 SP5 and earlier 

        else 
          begin 
            r := TRegistry.Create;
            r.RootKey := HKEY_LOCAL_MACHINE; 
            r.OpenKey('SYSTEM\CurrentControlSet\Control\ProductOptions',False); 
            ts := AnsiUpperCase(R.ReadString('ProductType'));
            r.Free; 
            if ansisametext(ts,'WINNT') then 
              begin 
                Result.Kind.AsString := 'Workstation'; 
              end 
            else if ansisametext(ts,'LANMANNT') then 
              begin
                Result.Kind.AsString := 'Server'; 
              end 
            else if ansisametext(ts,'SERVERNT') then 
              begin 
                Result.Kind.AsString := 'Advanced Server'; 
              end; 
            Result.Kind.AsString := Result.Kind.AsString + format(' %d.%d ',[osvi.dwMajorVersion, osvi.dwMinorVersion] ); 
          end; 

        // Display service pack (if any) and build number.

        if ( osvi.dwMajorVersion = 4 ) and ansisametext( osvi.szCSDVersion, 'Service Pack 6' ) then 
          begin 

            r := TRegistry.Create; 
            r.RootKey := HKEY_LOCAL_MACHINE; 

            // Test for SP6 versus SP6a. 
            if r.OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Hotfix\Q246009',False) then
              Result.ServicePack := format('Service Pack 6a (Build %d) ' + #13#10, [osvi.dwBuildNumber and $FFFF])
            else 
              Result.ServicePack := format('%s (Build %d) ' + #13#10, [osvi.szCSDVersion, 
                                                                       osvi.dwBuildNumber and $FFFF]); 
            r.Free; 
          end 

        // Windows NT 3.51 and earlier or Windows 2000 and later 

        else 
          Result.ServicePack := format('%s (Build %d) ' + #13#10, [osvi.szCSDVersion, 
                                                                   osvi.dwBuildNumber and $FFFF]);

        Result.Full := format('%s %s',[Result.Product,Result.Kind.AsString]);
      end; 

    // Test for the Windows 95 product family.
    VER_PLATFORM_WIN32_WINDOWS : 
      begin 

        Result.Kind.AsType := wptWorkstation; 
        Result.ServicePack := osvi.szCSDVersion; 

        if (osvi.dwMajorVersion = 4 ) and ( osvi.dwMinorVersion = 0 ) then 
          begin 
            Result.Product := 'Microsoft Windows 95';
            Result.OSKind  := win95; 
            if ( osvi.szCSDVersion[1] = 'C' ) or ( osvi.szCSDVersion[1] = 'B' ) then 
              begin
                Result.Kind.AsString := 'OSR2'; 
                Result.OSKind  := win95OSR2; 
              end;
            Result.Full := format('%s %s',[Result.Product,Result.Kind.AsString]); 
          end; 

        if (osvi.dwMajorVersion = 4 ) and ( osvi.dwMinorVersion = 10 ) then 
          begin 
            Result.Product := 'Microsoft Windows 98';
            Result.OSKind  := win98; 
            if ( osvi.szCSDVersion[1] = 'A' ) then 
              begin
                Result.Kind.AsString := 'SE'; 
                Result.OSKind  := win98se;
              end;

            Result.Full := format('%s %s',[Result.Product,Result.Kind.AsString]); 
          end;

        if (osvi.dwMajorVersion = 4 ) and ( osvi.dwMinorVersion = 90) then 
          begin
            Result.Product := 'Microsoft Windows Millennium Edition'; 
            Result.Full := format('%s',[Result.Product]);
            Result.OSKind  := winME;
          end; 
      end; 

    VER_PLATFORM_WIN32s: 
      begin 
        Result.Product := 'Microsoft Win32s'; 
        Result.Kind.AsType := wptWorkstation;
        Result.Full := format('%s',[Result.Product]); 
        Result.OSKind  := win31; 
      end; 
  end;

  Result.ServicePack := Trim(Result.ServicePack); 

end;

end.

Przykładowe użycie tego modułu wygląda tak:

procedure TForm1.Button1Click(Sender: TObject);
var
  OS: TWindowsTypeEx;
begin
  OS:= GetWindowsOS;
  Memo.Clear;
  with Memo.Lines do
  begin
    Add('Pełna nazwa systemu: ' + OS.Full);
    Add('Nazwa systemu: ' + OS.Product);
    Add('Rodzaj systemu: ' + OS.Kind.AsString);
    Add('Wersja systemu: ' + OS.OSVersion.AsString);
    Add('Service pack: ' + OS.ServicePack);
    Add('Wersja service pack: ' + OS.ServicePackVersion.AsString);
  end;
end;

4 komentarzy

Mój program napisany w języku C (źródła Dev-C++, Open Watcom IDE) do sprawdzania wersji systemu
Windows (od 3.1 do 8). Znajduje się na stronie (w budowie): http://romanworkshop.zz.mu/
w dziale WinAPI/Windows Version Checker.

@Ktos: msdn polecam jako lekturę obowiązkową przed dobranocką
A jak już jesteś taki oświecony w temacie to może zaprezentujesz nam swój kod albo chociaż przetestujesz kod który podałem. Wtedy nawet chętnie przyjmę kilka słów krytyki co do moich wypocin.
Może też być Se7en i mi to wisi jak jest. Taki miałem kaprys.

Nie "Windows Seven", a "Windows 7" jak już, bo tak się ten system nazywa.

Nawiasem - nie uruchamiałem tej funkcji (nie mam Delphi), ale tak z analizy kodu to mam wrażenie, że o ile rozróżnia te tzw. wersje SKU np. dla Windows Server 2003, to już nie robi tego dla Visty czy dla Servera 2008. Wraz z Vistą namnożyło się ich trochę, może to być dla niektórych istotne.

Dla Windows Vista i nowszych można by skorzystać z funkcji GetProductInfo(). Przydatne też może być skorzystanie z GetSystemMetrics() by wykryć (podobnie jak jest zrobione wykrycie 2003 R2) specyficzne odmiany XP jak Tablet PC Edition, Media Center Edition czy Starter.

A tak nawiasem to nadal nie uwzględnione - nawet przy moich uwagach - są wszystkie wersje Windows ;-)

U mnie funkcja GetWinowsOS wypluwa to:
Pełna nazwa systemu: Microsoft Windows XP Professional
Nazwa systemu: Microsoft Windows XP
Rodzaj systemu: Professional
Wersja systemu: 5.1
Service pack: Dodatek Service Pack 3 (Build 2600)
Wersja service pack: 3.0