/*
 * Xailer source code:
 *
 * SysVer.prg
 * Clase TSysVer
 *
 * Copyright 2003, 2019 Pedro Gil
 * Copyright 2003, 2019 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"
#include "WinNT.api"
#include "WinReg.api"


//--------------------------------------------------------------------------

CLASS XSysVer FROM TComponent

PUBLIC:
   DATA nMemoryRAM         INIT 0   READONLY
   DATA nMajorVersion      INIT 0   READONLY
   DATA nMinorVersion      INIT 0   READONLY
   DATA nBuildNumber       INIT 0   READONLY
   DATA nPlatformId        INIT 0   READONLY
   DATA cCSDVersion        INIT ""  READONLY
   DATA nServicePackMajor  INIT 0   READONLY
   DATA nServicePackMinor  INIT 0   READONLY
   DATA nSuiteMask         INIT 0   READONLY
   DATA nProductType       INIT 0   READONLY

   DATA nProcessorArch     INIT 0   READONLY
   DATA nProductInfo       INIT 0   READONLY

   DATA cVersionId         INIT ""  READONLY
   DATA nReleaseId         INIT 0   READONLY

   DATA lIsWin98           INIT .F. READONLY
   DATA lIsWinMe           INIT .F. READONLY
   DATA lIsWin2000         INIT .F. READONLY
   DATA lIsWinXP           INIT .F. READONLY
   DATA lIsWinXP64         INIT .F. READONLY
   DATA lIsWinServer2003   INIT .F. READONLY
   DATA lIsWinServer2003R2 INIT .F. READONLY
   DATA lIsWinHomeServer   INIT .F. READONLY
   DATA lIsWinVista        INIT .F. READONLY
   DATA lIsWinServer2008   INIT .F. READONLY
   DATA lIsWinServer2008R2 INIT .F. READONLY
   DATA lIsWin7            INIT .F. READONLY
   DATA lIsWinServer2012   INIT .F. READONLY
   DATA lIsWin8            INIT .F. READONLY
   DATA lIsWinServer2012R2 INIT .F. READONLY
   DATA lIsWin81           INIT .F. READONLY
   DATA lIsWin10           INIT .F. READONLY
   DATA lIsWinServer2016   INIT .F. READONLY
   DATA lIsWinServer2019   INIT .F. READONLY
   DATA lIsWin11           INIT .F. READONLY

   DATA lIsWow64           INIT .F. READONLY

   DATA cSysName           INIT "Microsoft Windows " READONLY
   DATA cSysVer            INIT ""  READONLY

   METHOD Create( oParent ) CONSTRUCTOR

PROTECTED:
   METHOD SysInfo()
   METHOD SysRelease()

ENDCLASS

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XSysVer

   ::Super:Create( oParent )

   ::SysInfo()

   DO CASE
      CASE ::nPlatformId == VER_PLATFORM_WIN32_WINDOWS
         IF ::nMajorVersion == 4
            ::lIsWin98 := ::nMinorVersion == 10 .AND. ::nBuildNumber == 1998
            ::lIsWinMe := ::nMinorVersion == 90 .AND. ::nBuildNumber  > 2183
         ENDIF

      CASE ::nPlatformId == VER_PLATFORM_WIN32_NT
         IF ::nMajorVersion == 5
            ::lIsWin2000 := ::nMinorVersion == 0
            ::lIsWinXP   := ::nMinorVersion == 1
         ENDIF

         IF ::nMajorVersion == 6
            IF ::nMinorVersion == 0
               IF ::nProductType == VER_NT_WORKSTATION
                  ::lIsWinVista := .T.
               ELSE
                  ::lIsWinServer2008 := .T.
               ENDIF
            ELSEIF ::nMinorVersion == 1
               IF ::nProductType == VER_NT_WORKSTATION
                  ::lIsWin7 := .T.
               ELSE
                  ::lIsWinServer2008R2 := .T.
               ENDIF
            ELSEIF ::nMinorVersion == 2
               IF ::nProductType == VER_NT_WORKSTATION
                  ::lIsWin8 := .T.
               ELSE
                  ::lIsWinServer2012 := .T.
               ENDIF
            ELSEIF ::nMinorVersion == 3
               IF ::nProductType == VER_NT_WORKSTATION
                  ::lIsWin81 := .T.
               ELSE
                  ::lIsWinServer2012R2 := .T.
               ENDIF
            ENDIF
         ENDIF

         IF ::nMajorVersion == 10
            IF ::nMinorVersion == 0
               IF ::nProductType == VER_NT_WORKSTATION
                  IF ::nBuildNumber >= 22000
                     ::lIsWin11 := .T.
                  ELSE
                     ::lIsWin10 := .T.
                  ENDIF
               ELSEIF ::nBuildNumber == 14393
                  ::lIsWinServer2016 := .T.
               ELSEIF ::nBuildNumber == 17763
                  ::lIsWinServer2019 := .T.
               ENDIF
            ENDIF
         ENDIF
   ENDCASE

   DO CASE
      CASE ::lIsWin98           ; ::cSysName += "98"
      CASE ::lIsWinMe           ; ::cSysName += "Me"
      CASE ::lIsWin2000         ; ::cSysName += "2000"
      CASE ::lIsWinXP           ; ::cSysName += "XP"
      CASE ::lIsWinXP64         ; ::cSysName += "XP Professional x64 Edition"
      CASE ::lIsWinServer2003   ; ::cSysName += "Server 2003"
      CASE ::lIsWinServer2003R2 ; ::cSysName += "Server 2003 R2"
      CASE ::lIsWinHomeServer   ; ::cSysName += "Home Server"
      CASE ::lIsWinVista        ; ::cSysName += "Vista"
      CASE ::lIsWinServer2008   ; ::cSysName += "Server 2008"
      CASE ::lIsWinServer2008R2 ; ::cSysName += "Server 2008 R2"
      CASE ::lIsWin7            ; ::cSysName += "7"
      CASE ::lIsWinServer2012   ; ::cSysName += "Server 2012"
      CASE ::lIsWin8            ; ::cSysName += "8"
      CASE ::lIsWinServer2012R2 ; ::cSysName += "Server 2012 R2"
      CASE ::lIsWin81           ; ::cSysName += "8.1"
      CASE ::lIsWin10           ; ::cSysName += "10"
      CASE ::lIsWinServer2016   ; ::cSysName += "Server 2016"
      CASE ::lIsWinServer2019   ; ::cSysName += "Server 2019"
      CASE ::lIsWin11           ; ::cSysName += "11"
      OTHERWISE                 ; ::cSysName := LT( XA_MSG_UNKNOWN_WINDOWS_VERSION )
   ENDCASE

   DO CASE
      CASE ::nMajorVersion >= 6
         IF ::nProductInfo == PRODUCT_ULTIMATE
            ::cSysName += " Ultimate Edition"
         ELSEIF ::nProductInfo == PRODUCT_HOME_BASIC
            ::cSysName += " Home Basic Edition"
         ELSEIF ::nProductInfo == PRODUCT_HOME_PREMIUM
            ::cSysName += " Home Premium Edition"
         ELSEIF ::nProductInfo == PRODUCT_ENTERPRISE
            ::cSysName += " Enterprise Edition"
         ELSEIF ::nProductInfo == PRODUCT_BUSINESS
            ::cSysName += " Business Edition"
         ELSEIF ::nProductInfo == PRODUCT_STARTER
            ::cSysName += " Starter Edition"
         ELSEIF ::nProductInfo == PRODUCT_CLUSTER_SERVER
            ::cSysName += " Cluster Server Edition"
         ELSEIF ::nProductInfo == PRODUCT_DATACENTER_SERVER
            ::cSysName += " Datacenter Edition"
         ELSEIF ::nProductInfo == PRODUCT_DATACENTER_SERVER_CORE
            ::cSysName += " Datacenter Edition (core installation)"
         ELSEIF ::nProductInfo == PRODUCT_ENTERPRISE_SERVER
            ::cSysName += " Enterprise Edition"
         ELSEIF ::nProductInfo == PRODUCT_ENTERPRISE_SERVER_CORE
            ::cSysName += " Enterprise Edition (core installation)"
         ELSEIF ::nProductInfo == PRODUCT_ENTERPRISE_SERVER_IA64
            ::cSysName += " Enterprise Edition for Itanium-based System"
         ELSEIF ::nProductInfo == PRODUCT_SMALLBUSINESS_SERVER
            ::cSysName += " Small Business Server"
         ELSEIF ::nProductInfo == PRODUCT_SMALLBUSINESS_SERVER_PREMIUM
            ::cSysName += " Small Business Server Premium Edition"
         ELSEIF ::nProductInfo == PRODUCT_STANDARD_SERVER
            ::cSysName += " Standard Edition"
         ELSEIF ::nProductInfo == PRODUCT_STANDARD_SERVER_CORE
            ::cSysName += " Standard Edition (core installation)"
         ELSEIF ::nProductInfo == PRODUCT_WEB_SERVER
            ::cSysName += " Web Server Edition"
         ELSEIF ::nProductInfo == PRODUCT_PROFESSIONAL
            ::cSysName += " Professional"
         ELSEIF ::nProductInfo == PRODUCT_CORE
            ::cSysName += " Home"
         ENDIF

         IF ::nProcessorArch == PROCESSOR_ARCHITECTURE_AMD64
            ::cSysName += " - 64 bits"
         ELSEIF ::nProcessorArch == PROCESSOR_ARCHITECTURE_INTEL
            ::cSysName += " - 32 bits"
         ENDIF

      CASE ::nProductType == VER_NT_WORKSTATION .AND. ::nProcessorArch != PROCESSOR_ARCHITECTURE_AMD64
         IF ::nMajorVersion >= 5
            ::cSysName += IIf( lAnd( ::nSuiteMask, VER_SUITE_PERSONAL ), ;
                               " Home Edition", " Professional" )
         ENDIF

      CASE ::nProductType == VER_NT_SERVER .OR. ::nProductType == VER_NT_DOMAIN_CONTROLLER
         IF ::nMajorVersion == 5 .and. ::nMinorVersion == 2
            IF ::nProcessorArch == PROCESSOR_ARCHITECTURE_IA64
               IF lAnd( ::nSuiteMask, VER_SUITE_DATACENTER )
                  ::cSysName += " Datacenter Edition for Itanium-based Systems"
               ELSEIF lAnd( ::nSuiteMask, VER_SUITE_ENTERPRISE )
                  ::cSysName += " Enterprise Edition for Itanium-based Systems"
               ENDIF
            ELSEIF ::nProcessorArch == PROCESSOR_ARCHITECTURE_AMD64
               IF lAnd( ::nSuiteMask, VER_SUITE_DATACENTER )
                  ::cSysName += " Datacenter x64 Edition"
               ELSEIF lAnd( ::nSuiteMask, VER_SUITE_ENTERPRISE )
                  ::cSysName += " Enterprise x64 Edition"
               ELSE
                  ::cSysName += " Standard x64 Edition"
               ENDIF
            ELSE
               IF lAnd( ::nSuiteMask, VER_SUITE_COMPUTE_SERVER )
                  ::cSysName += " Compute Cluster Edition"
               ELSEIF lAnd( ::nSuiteMask, VER_SUITE_DATACENTER )
                  ::cSysName += " Datacenter Edition"
               ELSEIF lAnd( ::nSuiteMask, VER_SUITE_ENTERPRISE )
                  ::cSysName += " Enterprise Edition"
               ELSEIF ::nSuiteMask == VER_SUITE_BLADE
                  ::cSysName += " Web Edition"
               ELSE
                  ::cSysName += " Standard Edition"
               ENDIF
            ENDIF
         ENDIF

         IF ::lIsWin2000
            IF lAnd( ::nSuiteMask, VER_SUITE_DATACENTER )
               ::cSysName += " Datacenter Server"
            ELSEIF lAnd( ::nSuiteMask, VER_SUITE_ENTERPRISE )
               ::cSysName += " Advanced Server"
            ELSE
               ::cSysName += " Server"
            ENDIF
         ENDIF
   ENDCASE

   ::SysRelease()
   ::lIsWow64 := XA_IsWow64()

   ::cSysVer := Ltrim( Str( ::nMajorVersion ) ) + "." + ;
                Ltrim( Str( ::nMinorVersion ) ) + "." + ;
                Ltrim( Str( ::nBuildNumber ) )  + " " + ;
                IIf( Empty( ::cCSDVersion ), "", ::cCSDVersion + " " ) + ;
                LT( XA_MSG_WINDOWS_BUILD ) + Ltrim( Str( ::nBuildNumber ) )

RETURN Self

//--------------------------------------------------------------------------

METHOD SysRelease() CLASS XSysVer

   IF ::lIsWin10 .OR. ::lIsWin11
      WITH OBJECT TRegistry():New()
         :Root := HKEY_LOCAL_MACHINE

         IF :OpenKey( "SOFTWARE\Microsoft\Windows NT\CurrentVersion", KEY_READ ) == 0
            ::cVersionId := :GetString( "DisplayVersion" )
            ::nReleaseId := Val( :GetString( "ReleaseId" ) )
         ENDIF

         :CloseKey()
      END
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#define _WIN32_IE 0x600

#include <windows.h>
#include <xailer.h>
#if ( defined(__MINGW32__) || defined(__MINGW64__) ) && ( __GNUC__ < 7 )
#include <ddk\ntddk.h>
#else
#include <winnt.h>
#endif

#define SM_SERVERR2  89
#define PROCESSOR_ARCHITECTURE_AMD64  9
#define VER_SUITE_WH_SERVER           0x00008000

typedef void ( WINAPI * PGNSI )( LPSYSTEM_INFO );
typedef HB_BOOL ( WINAPI * PGPI )( DWORD, DWORD, DWORD, DWORD, PDWORD );
typedef HB_LONG ( WINAPI * PGVI )( PRTL_OSVERSIONINFOEXW );
typedef HB_BOOL ( WINAPI * PGSM )( PULONGLONG );

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSYSVER_SYSINFO )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HMODULE hKernel = GetModuleHandle( "kernel32.dll" );
   OSVERSIONINFOEX osvi;
   SYSTEM_INFO si;
   PGNSI pGNSI;
   HB_BOOL bOk, bVerEx;

   ZeroMemory( &si, sizeof( SYSTEM_INFO ) );
   ZeroMemory( &osvi, sizeof( OSVERSIONINFOEX ) );

   osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );

   bVerEx = bOk = GetVersionEx( ( OSVERSIONINFO * ) &osvi );

   if( ! bVerEx )
   {
      osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
      bOk = GetVersionEx( ( OSVERSIONINFO * ) &osvi );
   }

   if( bOk )
   {
      if( osvi.dwMajorVersion >= 6 )
      {
         RTL_OSVERSIONINFOEXW pOvi;
         PGPI pGPI;
         PGSM pGSM;
         PGVI pGVI;
         DWORD dwType;
         HB_ULONGLONG ulMemory;

         ZeroMemory( &pOvi, sizeof( RTL_OSVERSIONINFOEXW ) );
         pOvi.dwOSVersionInfoSize = sizeof( RTL_OSVERSIONINFOEXW );

         if( ( pGVI = ( PGVI ) GetProcAddress( GetModuleHandle( "ntdll.dll" ), "RtlGetVersion" ) ) != NULL )
         {
            if( pGVI( &pOvi ) == 0 )
            {
               char * szCSDVersion = WideToAnsi( pOvi.szCSDVersion );

               XA_ObjSendNL( Self, "_nMajorVersion", pOvi.dwMajorVersion );
               XA_ObjSendNL( Self, "_nMinorVersion", pOvi.dwMinorVersion );
               XA_ObjSendNL( Self, "_nBuildNumber",  pOvi.dwBuildNumber & 0xFFFF );
               XA_ObjSendNL( Self, "_nPlatformId",   pOvi.dwPlatformId );
               XA_ObjSendC ( Self, "_cCSDVersion",   szCSDVersion );
               XA_ObjSendNL( Self, "_nServicePackMajor", pOvi.wServicePackMajor );
               XA_ObjSendNL( Self, "_nServicePackMinor", pOvi.wServicePackMinor );
               XA_ObjSendNL( Self, "_nSuiteMask",    pOvi.wSuiteMask );
               XA_ObjSendNL( Self, "_nProductType",  pOvi.wProductType );

               hb_xfree( szCSDVersion );
            }
         }

         if( ( pGPI = ( PGPI ) GetProcAddress( hKernel, "GetProductInfo" ) ) != NULL )
         {
            pGPI( pOvi.dwMajorVersion, pOvi.dwMinorVersion, pOvi.wServicePackMajor, pOvi.wServicePackMinor, &dwType );
            XA_ObjSendNL( Self, "_nProductInfo", dwType );
         }

         if( ( pGSM = ( PGSM ) GetProcAddress( hKernel, "GetPhysicallyInstalledSystemMemory" ) ) != NULL )
         {
            pGSM( &ulMemory );
            XA_ObjSendNL( Self, "_nMemoryRAM", ulMemory );
         }
      }
      else
      {
         XA_ObjSendNL( Self, "_nMajorVersion", osvi.dwMajorVersion );
         XA_ObjSendNL( Self, "_nMinorVersion", osvi.dwMinorVersion );
         XA_ObjSendNL( Self, "_nBuildNumber",  osvi.dwBuildNumber & 0xFFFF );
         XA_ObjSendNL( Self, "_nPlatformId",   osvi.dwPlatformId );
         XA_ObjSendC ( Self, "_cCSDVersion",   osvi.szCSDVersion );

         if( bVerEx )
         {
            XA_ObjSendNL( Self, "_nServicePackMajor", osvi.wServicePackMajor );
            XA_ObjSendNL( Self, "_nServicePackMinor", osvi.wServicePackMinor );
            XA_ObjSendNL( Self, "_nSuiteMask",   osvi.wSuiteMask );
            XA_ObjSendNL( Self, "_nProductType", osvi.wProductType );
         }
      }

      if( ( pGNSI = ( PGNSI ) GetProcAddress( hKernel, "GetNativeSystemInfo" ) ) != NULL )
         pGNSI (&si );
      else
         GetSystemInfo( &si );

      XA_ObjSendNL( Self, "_nProcessorArch", si.wProcessorArchitecture );

      if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
      {
         if( GetSystemMetrics( SM_SERVERR2 ) )
            XA_ObjSendL( Self, "_lIsWinServer2003R2", HB_TRUE );
         else if( osvi.wSuiteMask == VER_SUITE_WH_SERVER )
            XA_ObjSendL( Self, "_lIsWinHomeServer", HB_TRUE );
         else if( osvi.wProductType == VER_NT_WORKSTATION &&
             si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
            XA_ObjSendL( Self, "_lIsWinXP64", HB_TRUE );
         else
            XA_ObjSendL( Self, "_lIsWinServer2003", HB_TRUE );
      }
   }

   hb_ret();
}

#pragma ENDDUMP

//--------------------------------------------------------------------------