//--------------------------------------------------------------------- // Windows Version Pascal Source // // Create by: Kang Sin-young (2004.01.25 Last Modify) //--------------------------------------------------------------------- //--------------------------------------------------------------------- // GetWindowsVersion Pascal Source // From https://github.com/yypbd/yypbd-Delphi-Libs/blob/master/lib/WindowsVersion.pas // Create by: Young-pil Yang (2014.05.28 Last Modify) //--------------------------------------------------------------------- unit EM.WinOSVersion; interface uses WinApi.Windows, WinApi.Messages, SysUtils, Variants, StrUtils, System.Win.Registry; type TGetProductInfo = function (dwOsMajorVer, dwOSMinorVerion, dwSpMajorVer, dwSpMinorVer : DWORD; pdwReturnProductType : PDWORD):Boolean; stdcall; WKSTA_INFO_100 = record wki100_platform_id: DWORD; wki100_computername: LPWSTR; wki100_langroup: LPWSTR; wki100_ver_major: DWORD; wki100_ver_minor: DWORD; end; LPWKSTA_INFO_100 = ^WKSTA_INFO_100; _USER_INFO_0 = record usri0_name: LPWSTR; end; TWinVerSub = record Major, Minor, Build: DWORD; end; TWinVerInfo = record WinID, WinVer, WinName, ServicePack: String; Version: TWinVerSub; end; _OSVERSIONINFOEXA = record dwOSVersionInfoSize: DWORD; dwMajorVersion: DWORD; dwMinorVersion: DWORD; dwBuildNumber: DWORD; dwPlatformId: DWORD; szCSDVersion: array[0..127] of AnsiChar; { Maintenance string for PSS usage } wServicePackMajor: WORD; wServicePackMinor: WORD; wSuiteMask: WORD; wProductType: BYTE; wReserved: BYTE; end; {$EXTERNALSYM _OSVERSIONINFOEXA} _OSVERSIONINFOEXW = record dwOSVersionInfoSize: DWORD; dwMajorVersion: DWORD; dwMinorVersion: DWORD; dwBuildNumber: DWORD; dwPlatformId: DWORD; szCSDVersion: array[0..127] of WideChar; { Maintenance string for PSS usage } wServicePackMajor: WORD; wServicePackMinor: WORD; wSuiteMask: WORD; wProductType: BYTE; wReserved: BYTE; end; {$EXTERNALSYM _OSVERSIONINFOEXW} OSVERSIONINFOEXA = _OSVERSIONINFOEXA; OSVERSIONINFOEXW = _OSVERSIONINFOEXW; {$EXTERNALSYM OSVERSIONINFOEXA} {$EXTERNALSYM OSVERSIONINFOEXW} OSVERSIONINFOEX = OSVERSIONINFOEXA; {$EXTERNALSYM OSVERSIONINFOEX} TOSVersionInfoExA = OSVERSIONINFOEXA; TOSVersionInfoExW = OSVERSIONINFOEXW; const NERR_Success = 0; SERVICE_MAX_COUNT = 10; VER_EQUAL = 1; VER_SERVER_NT = $80000000; {$EXTERNALSYM VER_SERVER_NT} VER_WORKSTATION_NT = $40000000; {$EXTERNALSYM VER_WORKSTATION_NT} VER_SUITE_SMALLBUSINESS = $00000001; {$EXTERNALSYM VER_SUITE_SMALLBUSINESS} VER_SUITE_ENTERPRISE = $00000002; {$EXTERNALSYM VER_SUITE_ENTERPRISE} VER_SUITE_BACKOFFICE = $00000004; {$EXTERNALSYM VER_SUITE_BACKOFFICE} VER_SUITE_COMMUNICATIONS = $00000008; {$EXTERNALSYM VER_SUITE_COMMUNICATIONS} VER_SUITE_TERMINAL = $00000010; {$EXTERNALSYM VER_SUITE_TERMINAL} VER_SUITE_SMALLBUSINESS_RESTRICTED = $00000020; {$EXTERNALSYM VER_SUITE_SMALLBUSINESS_RESTRICTED} VER_SUITE_EMBEDDEDNT = $00000040; {$EXTERNALSYM VER_SUITE_EMBEDDEDNT} VER_SUITE_DATACENTER = $00000080; {$EXTERNALSYM VER_SUITE_DATACENTER} VER_SUITE_SINGLEUSERTS = $00000100; {$EXTERNALSYM VER_SUITE_SINGLEUSERTS} VER_SUITE_PERSONAL = $00000200; {$EXTERNALSYM VER_SUITE_PERSONAL} VER_SUITE_BLADE = $00000400; {$EXTERNALSYM VER_SUITE_BLADE} VER_SUITE_EMBEDDED_RESTRICTED = $00000800; {$EXTERNALSYM VER_SUITE_EMBEDDED_RESTRICTED} VER_SUITE_SECURITY_APPLIANCE = $00001000; {$EXTERNALSYM VER_SUITE_SECURITY_APPLIANCE} VER_NT_WORKSTATION = $0000001; {$EXTERNALSYM VER_NT_WORKSTATION} VER_NT_DOMAIN_CONTROLLER = $0000002; {$EXTERNALSYM VER_NT_DOMAIN_CONTROLLER} VER_NT_SERVER = $0000003; {$EXTERNALSYM VER_NT_SERVER} //GetProductInfo vista 이상에서만 사용 PRODUCT_BUSINESS = $00000006; PRODUCT_BUSINESS_N = $00000010; PRODUCT_CLUSTER_SERVER = $00000012; PRODUCT_DATACENTER_SERVER = $00000008; PRODUCT_DATACENTER_SERVER_CORE = $0000000C; PRODUCT_DATACENTER_SERVER_CORE_V = $00000027; PRODUCT_DATACENTER_SERVER_V = $00000025; PRODUCT_ENTERPRISE = $00000004; PRODUCT_ENTERPRISE_E = $00000046; PRODUCT_ENTERPRISE_N = $0000001B; PRODUCT_ENTERPRISE_SERVER = $0000000A; PRODUCT_ENTERPRISE_SERVER_CORE = $0000000E; PRODUCT_ENTERPRISE_SERVER_CORE_V = $00000029; PRODUCT_ENTERPRISE_SERVER_IA64 = $0000000F; PRODUCT_ENTERPRISE_SERVER_V = $00000026; PRODUCT_HOME_BASIC = $00000002; PRODUCT_HOME_BASIC_E = $00000043; PRODUCT_HOME_BASIC_N = $00000005; PRODUCT_HOME_PREMIUM = $00000003; PRODUCT_ULTIMATE = $00000001; PRODUCT_PROFESSIONAL = $00000030; PRODUCT_PROFESSIONAL_N = $00000031; PRODUCT_STARTER = $0000000B; PRODUCT_SMALLBUSINESS_SERVER = $00000009; PRODUCT_SMALLBUSINESS_SERVER_PREMIUM = $00000019; PRODUCT_STANDARD_SERVER = $00000007; PRODUCT_STANDARD_SERVER_CORE = $0000000D; PRODUCT_WEB_SERVER = $00000011; var MajorCache: DWORD; MinorCache: DWORD; ServicePackCache: DWORD; IsServerCache: Boolean; function NetWkstaGetInfo(ServerName: LPWSTR; Level: DWORD; BufPtr: Pointer) : Longint; stdcall; external 'netapi32.dll' Name 'NetWkstaGetInfo'; function NetApiBufferFree(Buffer: Pointer): Longint; stdcall; external 'netapi32.dll' Name 'NetApiBufferFree'; {$IFDEF UNICODE} function VerifyVersionInfo(var LPOSVERSIONINFOEX: OSVERSIONINFOEX; dwTypeMask: DWORD; dwlConditionMask: int64): BOOL; stdcall; external kernel32 name 'VerifyVersionInfoW'; {$ELSE} function VerifyVersionInfo(var LPOSVERSIONINFOEX: OSVERSIONINFOEX; dwTypeMask: DWORD; dwlConditionMask: int64): BOOL; stdcall; external kernel32 name 'VerifyVersionInfoA'; {$ENDIF} function VerSetConditionMask(dwlConditionMask: int64; dwTypeBitMask: DWORD; dwConditionMask: Byte): int64; stdcall; external kernel32; function GetVersionEx2(var lpVersionInformation: TOSVersionInfoExA): BOOL; stdcall; {$EXTERNALSYM GetVersionEx2} function GetVersionEx2A(var lpVersionInformation: TOSVersionInfoExA): BOOL; stdcall; {$EXTERNALSYM GetVersionEx2A} function GetVersionEx2W(var lpVersionInformation: TOSVersionInfoExW): BOOL; stdcall; {$EXTERNALSYM GetVersionEx2W} function GetWindowsVersion(var AMajor, AMinor: DWORD): Boolean; overload; function GetWindowsVersion(var AMajor, AMinor, AServicePack, ABuildNumber: DWORD; var AIsServer: Boolean): Boolean; overload; function GetWinVersion: TWinVerInfo; function ParseWinNT(p: TOSVersionInfoExW; IsEx: Boolean): TWinVerInfo; overload; function ParseWinNT(p: TOSVersionInfoExA; IsEx: Boolean): TWinVerInfo; overload; function ParseWin9x(p: TOSVersionInfo): TWinVerInfo; implementation uses System.Classes, Tocsg.Safe, Tocsg.Path, Tocsg.Strings, Tocsg.Registry, Tocsg.FileInfo; function GetVersionEx2; external kernel32 name 'GetVersionExA'; function GetVersionEx2A; external kernel32 name 'GetVersionExA'; function GetVersionEx2W; external kernel32 name 'GetVersionExW'; function GetWinVersion: TWinVerInfo; var rtnVerEx: TOSVersionInfoExA; rtnVer: TOSVersionInfo; rtnParse: TWinVerInfo; begin rtnVer.dwOSVersionInfoSize := sizeof(OSVERSIONINFO); //Get 1st OS Info GetVersionEx(rtnVer); if rtnVer.dwPlatformId = VER_PLATFORM_WIN32_NT then begin if rtnVer.dwMajorVersion < 5 then rtnParse := ParseWinNT(rtnVerEx, False) else begin rtnVerEx.dwOSVersionInfoSize := sizeof(TOSVersionInfoExA); //*WinNT/2000/XP/2003 GetVersionEx2(rtnVerEx); rtnParse := ParseWinNT(rtnVerEx, True); end; end else rtnParse := ParseWin9x(rtnVer); Result := rtnParse; end; function ParseWinNT(p: TOSVersionInfoExA; IsEx: Boolean): TWinVerInfo; function IsWin11: Boolean; var fi: TTgFileInfo; StrList: TStringList; begin Result := false; Guard(fi, TTgFileInfo.Create(GetSystemDir + 'kernel32.dll')); Guard(StrList, TStringList.Create); if SplitString(fi.Version, '.', StrList) > 3 then begin if StrToIntDef(StrList[2], -1) >= 22000 then Result := true; end; end; var rtn: TWinVerInfo; resVer: TRegistry; szProduct: String; procGetProductInfo : TGetProductInfo; hModule : THandle; ProdType : DWORD; dwMajor, dwMinor, dwService, dwBuildNum : DWORD; bIsServer : Boolean; begin GetWindowsVersion(dwMajor, dwMinor, dwService, dwBuildNum, bIsServer); p.dwMajorVersion := dwMajor; p.dwMinorVersion := dwMinor; p.dwBuildNumber := dwBuildNum; if not bIsServer then begin p.wProductType := VER_NT_WORKSTATION end; // 윈도우 8.0이 추가 되면서 다시 개선함 rtn.WinVer := 'Unknown'; case p.dwMajorVersion of 5 : case p.dwMinorVersion of 0 : rtn.WinName := '2000'; 1 : rtn.WinName := 'XP'; 2 : rtn.WinName := '2003 Server Family'; end; 6 : case p.dwMinorVersion of 0 : if p.wProductType = VER_NT_WORKSTATION then rtn.WinVer := 'Vista' else rtn.WinVer := 'Server 2008'; 1 : if p.wProductType = VER_NT_WORKSTATION then rtn.WinVer := '7' else rtn.WinVer := 'Server 2008 R2'; 2 : // 윈 8 정보 추가 if p.wProductType = VER_NT_WORKSTATION then rtn.WinVer := '8' else rtn.WinVer := 'Server 2012'; 3 : // 윈 8 정보 추가 if p.wProductType = VER_NT_WORKSTATION then rtn.WinVer := '8.1' else rtn.WinVer := 'Server 2012 R2'; end; 10 : begin // 윈도우 10 rtn.WinVer := '10'; case p.dwMinorVersion of 0 : ; // .. 하위 정보 확인 필요 end; // windows 11의 공식 메이저 버전은 10이다.. // 11인걸 판단하기 위해 'kernel32.dll'의 빌드번호가 22000 이상인지 확인한다. 22_0517 10:05:21 kku if IsWin11 then rtn.WinVer := '11'; end; 0 : begin // 안전모드에서는 실패한다. 22_1116 13:11:54 kku rtn.WinVer := ExtrNumStr(GetRegValueAsString(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion', 'ProductName')); if rtn.WinVer = '10' then begin if IsWin11 then rtn.WinVer := '11'; end else if rtn.WinVer = '' then rtn.WinVer := '?'; end; end; rtn.WinName := 'Windows ' + rtn.WinVer; //Get Product Substring if (IsEX) then begin case p.wProductType of VER_NT_WORKSTATION: begin if (p.dwMajorVersion = 4) then rtn.WinName := rtn.WinName + ' Workstation 4.0' else if (p.wSuiteMask and VER_SUITE_PERSONAL) = VER_SUITE_PERSONAL then rtn.WinName := rtn.WinName + ' Home Edition' else if p.dwMajorVersion = 6 then begin // 비스타의 경우.. 버전정보를 모르겠다.. 아직은.. end else rtn.WinName := rtn.WinName + ' Professional'; end; VER_NT_SERVER: begin if ((p.dwMajorVersion = 5) and (p.dwMinorVersion = 2)) then begin if (p.wSuiteMask and VER_SUITE_DATACENTER) = VER_SUITE_DATACENTER then rtn.WinName := rtn.WinName + ' Datacenter Edition' else if (p.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then rtn.WinName := rtn.WinName + ' Enterprise Edition' else if (p.wSuiteMask and VER_SUITE_BLADE) = VER_SUITE_BLADE then rtn.WinName := rtn.WinName + ' Web Edition' else rtn.WinName := rtn.WinName + ' Standard Edition'; end else if ((p.dwMajorVersion = 5) and (p.dwMinorVersion = 0)) then begin if (p.wSuiteMask and VER_SUITE_DATACENTER) = VER_SUITE_DATACENTER then rtn.WinName := rtn.WinName + ' Datacenter Server' else if (p.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then rtn.WinName := rtn.WinName + ' Advanced Server' else rtn.WinName := rtn.WinName + ' Server'; end else if (p.dwMajorVersion = 6) then else begin if (p.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then rtn.WinName := rtn.WinName + ' Server 4.0 Enterprise Edition' else rtn.WinName := rtn.WinName + ' Server 4.0'; end; end; end; {case of} if p.dwMajorVersion = 6 then begin hModule := GetModuleHandle('kernel32.dll'); procGetProductInfo := GetProcAddress( hModule ,'GetProductInfo'); if Assigned(procGetProductInfo) then begin procGetProductInfo(p.dwMajorVersion, p.dwMinorVersion, 0, 0, @ProdType); case ProdType of PRODUCT_ULTIMATE : rtn.WinName := rtn.WinName + ' Ultimate'; PRODUCT_PROFESSIONAL : rtn.WinName := rtn.WinName + ' Professional'; PRODUCT_HOME_PREMIUM : rtn.WinName := rtn.WinName + ' Home Premium Edition'; PRODUCT_HOME_BASIC : rtn.WinName := rtn.WinName + ' Home Basic Edition'; PRODUCT_ENTERPRISE : rtn.WinName := rtn.WinName + ' Enterprise Edition'; PRODUCT_BUSINESS : rtn.WinName := rtn.WinName + ' Business Edition'; PRODUCT_STARTER : rtn.WinName := rtn.WinName + ' Starter Edition'; PRODUCT_CLUSTER_SERVER : rtn.WinName := rtn.WinName + ' Cluster Server Edition'; PRODUCT_DATACENTER_SERVER : rtn.WinName := rtn.WinName + ' Datacenter Edition'; PRODUCT_DATACENTER_SERVER_CORE : rtn.WinName := rtn.WinName + ' Datacenter Edition (core installation)'; PRODUCT_ENTERPRISE_SERVER : rtn.WinName := rtn.WinName + ' Enterprise Edition'; PRODUCT_ENTERPRISE_SERVER_CORE : rtn.WinName := rtn.WinName + ' Enterprise Edition (core installation)'; PRODUCT_ENTERPRISE_SERVER_IA64 : rtn.WinName := rtn.WinName + ' Enterprise Edition for Itanium-based Systems)'; PRODUCT_SMALLBUSINESS_SERVER : rtn.WinName := rtn.WinName + ' Small Business Server'; PRODUCT_SMALLBUSINESS_SERVER_PREMIUM : rtn.WinName := rtn.WinName + ' Small Business Server Premium Edition'; PRODUCT_STANDARD_SERVER : rtn.WinName := rtn.WinName + ' Standard Edition'; PRODUCT_STANDARD_SERVER_CORE : rtn.WinName := rtn.WinName + ' Standard Edition (core installation)'; PRODUCT_WEB_SERVER : rtn.WinName := rtn.WinName + ' Web Server Edition'; end; FreeModule(hModule); end; end; end {If IsEx} else begin // Test for specific product on Windows NT 4.0 SP5 and earlier resVer := TRegistry.Create(KEY_READ); try resVer.RootKey := HKEY_LOCAL_MACHINE; resver.OpenKeyReadOnly('SYSTEM\\CurrentControlSet\\Control\\ProductOptions'); szProduct := resVer.ReadString('ProductType'); if (Strcomp('WINNT', PChar(szProduct)) = 0) then rtn.WinName := rtn.WinName + ' Workstation ' else if (Strcomp('LANMANNT', PChar(szProduct)) = 0) then rtn.WinName := rtn.WinName + ' Server ' else if (Strcomp('SERVERNT', PChar(szProduct)) = 0) then rtn.WinName := rtn.WinName + ' Advanced Server '; rtn.WinName := rtn.WinName + IntToStr(p.dwMajorVersion) + '.' + IntToStr(p.dwMinorVersion); finally resVer.Free; end; end;{else IsEx} //Get Version rtn.Version.Major := p.dwMajorVersion; rtn.Version.Minor := p.dwMinorVersion; rtn.Version.Build := p.dwBuildNumber; //Get Service Pack if ((p.dwMajorVersion = 4) and (lstrcmpiA(p.szCSDVersion, 'Service Pack 6' ) = 0)) then begin // Test for SP6 versus SP6a. resVer := TRegistry.Create(KEY_READ); try resVer.RootKey := HKEY_LOCAL_MACHINE; if resVer.OpenKeyReadOnly('SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009') then rtn.ServicePack := 'Service Pack 6a' else rtn.ServicePack := String(p.szCSDVersion); //warring 제거 finally resVer.Free; end; end else //Else Other All Version if Boolean(p.wServicePackMajor) or Boolean(p.wServicePackMinor) then begin rtn.ServicePack := 'Service Pack ' + intToStr(p.wServicePackMajor); if Boolean(p.wServicePackMinor) then rtn.ServicePack := rtn.ServicePack + '.' + IntToStr(p.wServicePackMinor); end else rtn.ServicePack := String(p.szCSDVersion); //Create ID String and Return rtn.WinID := 'Microsoft ' + rtn.WinName + '(Version ' + IntToStr(rtn.Version.Major) + '.' + IntToStr(rtn.Version.Minor) + ' Build ' + IntToStr(rtn.Version.Build) + ') ' + rtn.ServicePack; Result := rtn; end; function ParseWinNT(p: TOSVersionInfoExW; IsEx: Boolean): TWinVerInfo; var rtn: TWinVerInfo; resVer: TRegistry; szProduct: String; procGetProductInfo : TGetProductInfo; hModule : THandle; ProdType : DWORD; dwMajor, dwMinor, dwService, dwBuildNum : DWORD; bIsServer : Boolean; begin GetWindowsVersion(dwMajor, dwMinor, dwService, dwBuildNum, bIsServer); p.dwMajorVersion := dwMajor; p.dwMinorVersion := dwMinor; p.dwBuildNumber := dwBuildNum; if not bIsServer then begin p.wProductType := VER_NT_WORKSTATION end; //Get Windows Product if p.dwMajorVersion = 5 then begin if p.dwMinorVersion = 2 then rtn.WinName := 'Windows 2003 Server Family' else if p.dwMinorVersion = 1 then rtn.WinName := 'Windows XP' else if p.dwMinorVersion = 0 then rtn.WinName := 'Windows 2000'; end else if p.dwMajorVersion = 6 then if p.dwMinorVersion = 1 then begin if p.wProductType = VER_NT_WORKSTATION then rtn.WinName := 'Windows 7' else rtn.WinName := 'Windows Server 2008 R2'; end else if p.dwMinorVersion = 0 then begin if p.wProductType = VER_NT_WORKSTATION then rtn.WinName := 'Windows Vista' else rtn.WinName := 'Windows Server 2008'; end else rtn.WinName := 'Windows NT'; //Get Product Substring if (IsEX) then begin case p.wProductType of VER_NT_WORKSTATION: begin if (p.dwMajorVersion = 4) then rtn.WinName := rtn.WinName + ' Workstation 4.0' else if (p.wSuiteMask and VER_SUITE_PERSONAL) = VER_SUITE_PERSONAL then rtn.WinName := rtn.WinName + ' Home Edition' else if p.dwMajorVersion = 6 then begin // 비스타의 경우.. 버전정보를 모르겠다.. 아직은.. end else rtn.WinName := rtn.WinName + ' Professional'; end; VER_NT_SERVER: begin if ((p.dwMajorVersion = 5) and (p.dwMinorVersion = 2)) then begin if (p.wSuiteMask and VER_SUITE_DATACENTER) = VER_SUITE_DATACENTER then rtn.WinName := rtn.WinName + ' Datacenter Edition' else if (p.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then rtn.WinName := rtn.WinName + ' Enterprise Edition' else if (p.wSuiteMask and VER_SUITE_BLADE) = VER_SUITE_BLADE then rtn.WinName := rtn.WinName + ' Web Edition' else rtn.WinName := rtn.WinName + ' Standard Edition'; end else if ((p.dwMajorVersion = 5) and (p.dwMinorVersion = 0)) then begin if (p.wSuiteMask and VER_SUITE_DATACENTER) = VER_SUITE_DATACENTER then rtn.WinName := rtn.WinName + ' Datacenter Server' else if (p.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then rtn.WinName := rtn.WinName + ' Advanced Server' else rtn.WinName := rtn.WinName + ' Server'; end else if (p.dwMajorVersion = 6) then else begin if (p.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then rtn.WinName := rtn.WinName + ' Server 4.0 Enterprise Edition' else rtn.WinName := rtn.WinName + ' Server 4.0'; end; end; end; {case of} if p.dwMajorVersion = 6 then begin hModule := GetModuleHandle('kernel32.dll'); procGetProductInfo := GetProcAddress( hModule ,'GetProductInfo'); if Assigned(procGetProductInfo) then begin procGetProductInfo(p.dwMajorVersion, p.dwMinorVersion, 0, 0, @ProdType); case ProdType of PRODUCT_ULTIMATE : rtn.WinName := rtn.WinName + ' Ultimate'; PRODUCT_PROFESSIONAL : rtn.WinName := rtn.WinName + ' Professional'; PRODUCT_HOME_PREMIUM : rtn.WinName := rtn.WinName + ' Home Premium Edition'; PRODUCT_HOME_BASIC : rtn.WinName := rtn.WinName + ' Home Basic Edition'; PRODUCT_ENTERPRISE : rtn.WinName := rtn.WinName + ' Enterprise Edition'; PRODUCT_BUSINESS : rtn.WinName := rtn.WinName + ' Business Edition'; PRODUCT_STARTER : rtn.WinName := rtn.WinName + ' Starter Edition'; PRODUCT_CLUSTER_SERVER : rtn.WinName := rtn.WinName + ' Cluster Server Edition'; PRODUCT_DATACENTER_SERVER : rtn.WinName := rtn.WinName + ' Datacenter Edition'; PRODUCT_DATACENTER_SERVER_CORE : rtn.WinName := rtn.WinName + ' Datacenter Edition (core installation)'; PRODUCT_ENTERPRISE_SERVER : rtn.WinName := rtn.WinName + ' Enterprise Edition'; PRODUCT_ENTERPRISE_SERVER_CORE : rtn.WinName := rtn.WinName + ' Enterprise Edition (core installation)'; PRODUCT_ENTERPRISE_SERVER_IA64 : rtn.WinName := rtn.WinName + ' Enterprise Edition for Itanium-based Systems)'; PRODUCT_SMALLBUSINESS_SERVER : rtn.WinName := rtn.WinName + ' Small Business Server'; PRODUCT_SMALLBUSINESS_SERVER_PREMIUM : rtn.WinName := rtn.WinName + ' Small Business Server Premium Edition'; PRODUCT_STANDARD_SERVER : rtn.WinName := rtn.WinName + ' Standard Edition'; PRODUCT_STANDARD_SERVER_CORE : rtn.WinName := rtn.WinName + ' Standard Edition (core installation)'; PRODUCT_WEB_SERVER : rtn.WinName := rtn.WinName + ' Web Server Edition'; end; FreeModule(hModule); end; end; end {If IsEx} else begin // Test for specific product on Windows NT 4.0 SP5 and earlier resVer := TRegistry.Create(KEY_READ); try resVer.RootKey := HKEY_LOCAL_MACHINE; resver.OpenKeyReadOnly('SYSTEM\\CurrentControlSet\\Control\\ProductOptions'); szProduct := resVer.ReadString('ProductType'); if (Strcomp('WINNT', PChar(szProduct)) = 0) then rtn.WinName := rtn.WinName + ' Workstation ' else if (Strcomp('LANMANNT', PChar(szProduct)) = 0) then rtn.WinName := rtn.WinName + ' Server ' else if (Strcomp('SERVERNT', PChar(szProduct)) = 0) then rtn.WinName := rtn.WinName + ' Advanced Server '; rtn.WinName := rtn.WinName + IntToStr(p.dwMajorVersion) + '.' + IntToStr(p.dwMinorVersion); finally resVer.Free; end; end;{else IsEx} //Get Version rtn.Version.Major := p.dwMajorVersion; rtn.Version.Minor := p.dwMinorVersion; rtn.Version.Build := (p.dwBuildNumber and $FFFF); //Get Service Pack if ((p.dwMajorVersion = 4) and (lstrcmpW(p.szCSDVersion, 'Service Pack 6' ) = 0)) then begin // Test for SP6 versus SP6a. resVer := TRegistry.Create(KEY_READ); try resVer.RootKey := HKEY_LOCAL_MACHINE; if resVer.OpenKeyReadOnly('SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009') then rtn.ServicePack := 'Service Pack 6a' else rtn.ServicePack := p.szCSDVersion; finally resVer.Free; end; end else //Else Other All Version if Boolean(p.wServicePackMajor) or Boolean(p.wServicePackMinor) then begin rtn.ServicePack := 'Service Pack ' + intToStr(p.wServicePackMajor); if Boolean(p.wServicePackMinor) then rtn.ServicePack := rtn.ServicePack + '.' + IntToStr(p.wServicePackMinor); end else rtn.ServicePack := p.szCSDVersion; //Create ID String and Return rtn.WinID := 'Microsoft ' + rtn.WinName + #10#13'(Version ' + IntToStr(rtn.Version.Major) + '.' + IntToStr(rtn.Version.Minor) + ' Build ' + IntToStr(rtn.Version.Build) + ') ' + rtn.ServicePack; Result := rtn; end; function ParseWin9x(p: TOSVersionInfo): TWinVerInfo; var rtn: TWinVerInfo; begin if ((p.dwMajorVersion = 4) and (p.dwMinorVersion = 0)) then begin rtn.WinName := 'Windows 95'; if ((p.szCSDVersion[1] = 'C') or (p.szCSDVersion[1] = 'B')) then rtn.WinName := rtn.WinName + ' OSR2'; end else if ((p.dwMajorVersion = 4) and (p.dwMinorVersion = 10)) then begin rtn.WinName := 'Windows 98'; if (p.szCSDVersion[1] = 'A') then rtn.WinName := rtn.WinName + ' SE'; end else if ((p.dwMajorVersion = 4) and (p.dwMinorVersion = 90)) then rtn.WinName := 'Windows Millennium Edition'; rtn.Version.Major := p.dwMajorVersion; rtn.Version.Minor := p.dwMinorVersion; rtn.Version.Build := (p.dwBuildNumber and $FFFF); rtn.ServicePack := p.szCSDVersion; if ((p.szCSDVersion[1] = 'C') or (p.szCSDVersion[1] = 'B') or (p.szCSDVersion[1] = 'A')) then rtn.ServicePack := RightStr(rtn.ServicePack, Length(rtn.ServicePack) - 2); //Create ID String and Return rtn.WinID := 'Microsoft ' + rtn.WinName + #10#13'(Version ' + IntToStr(rtn.Version.Major) + '.' + IntToStr(rtn.Version.Minor) + ' Build ' + IntToStr(rtn.Version.Build) + ') ' + rtn.ServicePack; Result := rtn; end; function GetWindowsVersion(var AMajor, AMinor: DWORD): Boolean; var Buf: LPWKSTA_INFO_100; begin Result := False; if MajorCache <> 0 then begin AMajor := MajorCache; AMinor := MinorCache; Result := True; Exit; end; if NetWkstaGetInfo(nil, 100, @Buf) = NERR_Success then begin MajorCache := Buf.wki100_ver_major; AMajor := MajorCache; MinorCache := Buf.wki100_ver_minor; AMinor := MinorCache; NetApiBufferFree(Buf); Result := True; end; end; function GetWindowsVersion(var AMajor, AMinor, AServicePack, ABuildNumber: DWORD; var AIsServer: Boolean): Boolean; overload; var I: Integer; osvi: OSVERSIONINFOEX; ConditionMask: LONGLONG; begin Result := False; AMajor := 0; AMinor := 0; AServicePack := 0; ABuildNumber := 0; if not GetWindowsVersion(AMajor, AMinor) then exit; if ServicePackCache <> MAXDWORD then begin AServicePack := ServicePackCache; AIsServer := IsServerCache; Result := True; Exit; end; ZeroMemory(@osvi, SizeOf(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize := SizeOf(OSVERSIONINFOEX); ConditionMask := 0; ConditionMask := VerSetConditionMask(ConditionMask, VER_SERVICEPACKMAJOR, VER_EQUAL); for I := 0 to SERVICE_MAX_COUNT - 1 do begin osvi.wServicePackMajor := I; if VerifyVersionInfo(osvi, VER_SERVICEPACKMAJOR, ConditionMask) then begin ServicePackCache := I; AServicePack := ServicePackCache; ZeroMemory(@osvi, SizeOf(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize := SizeOf(OSVERSIONINFOEX); osvi.wProductType := VER_NT_SERVER; ConditionMask := 0; ConditionMask := VerSetConditionMask(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL); IsServerCache := VerifyVersionInfo(osvi, VER_PRODUCT_TYPE, ConditionMask); AIsServer := IsServerCache; Result := True; break; end; end; ConditionMask := 0; ConditionMask := VerSetConditionMask(ConditionMask, VER_BUILDNUMBER, VER_EQUAL); for I := 0 to 10000 do begin osvi.dwBuildNumber := I; if VerifyVersionInfo(osvi, VER_BUILDNUMBER, ConditionMask) then begin ABuildNumber := I; Result := True; Exit; end; end; end; initialization MajorCache := 0; MinorCache := 0; ServicePackCache := MAXDWORD; IsServerCache := False; end.