Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ How to detect Windows Server 2019?

Microsoft released Windows Server 2019 on October 2, 2018. From Windows 2000 and up until this Windows version, you could call a WinAPI function GetVersionEx with a struct OSVERSIONINFOEX and depending on the variables of dwMajorVersion, dwMinorVersion and wProductType determine Windows version, for example, Windows 8.1, Windows 10, Windows Server 2012 R2. The code everyone used was something like this:

OSVERSIONINFOEX osvi;
SecureZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (GetVersionEx(&osvi)) {
    if (osvi.dwMajorVersion == 10 &&
        osvi.dwMinorVersion == 0 &&
        osvi.wProductType != VER_NT_WORKSTATION) {
            Console->Log("We are running on Windows Server 2016");
        }
}

Judging from Wikipedia the Windows Server 2019 has the same version number of NT 10.0 as Server 2016. So the above code does not work anymore.

Also, Microsoft Docs contains the following note: GetVersionEx may be altered or unavailable for releases after Windows 8.1. Instead, use the Version Helper functions.

Unfortunately, the Version Helper functions does not have a function to detect Server 2019. Also, the strange thing is that Docs page about Targeting stops at the Windows 10, and does not talk about Server editions, while these Targeting manifests is mandatory for detecting OS above Windows 8.1 or Server 2012.

Update 1. As @IInspectable and @RbMm commented about usage of RtlGetVersion function. So I ran the following code (taken from this answer):

typedef LONG NTSTATUS, *PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)

typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);

RTL_OSVERSIONINFOW GetRealOSVersion() {
    HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
    if (hMod) {
        RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
        if (fxPtr != nullptr) {
            RTL_OSVERSIONINFOW rovi = { 0 };
            rovi.dwOSVersionInfoSize = sizeof(rovi);
            if ( STATUS_SUCCESS == fxPtr(&rovi) ) {
                return rovi;
            }
        }
    }
    RTL_OSVERSIONINFOW rovi = { 0 };
    return rovi;
}

And here are the results for Windows 10:

  • dwMajorVersion = 10
  • dwMinorVersion = 0
  • dwBuildNumber = 17134
  • dwPlatformId = 2

Windows Server 2019:

  • dwMajorVersion = 10
  • dwMinorVersion = 0
  • dwBuildNumber = 17763
  • dwPlatformId = 2

Update2. As requested, posting full info from OSVERSIONINFOEX struct that was obtained via GetVersionEx call with a manifest file containing all the Targets till Windows 10 (see the Targeting link above):

// Windows 10
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 17134
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 256  // 0x100
osvi.wProductType = 1
osvi.wReserved = 0

// Windows Server 2016
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 14393
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 400
osvi.wProductType = 3
osvi.wReserved = 0

// Windows Server 2019
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 17763
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 400  // 0x190
osvi.wProductType = 3
osvi.wReserved = 0

Update 3. Calling RtlGetVersion with a struct RTL_OSVERSIONINFOEXW we get exactly the same result as in Update 2.

like image 275
Maris B. Avatar asked Nov 20 '18 12:11

Maris B.


2 Answers

According to discussions in Windows Server 2019 version info:

[Windows] Server 2019 Datacenter Edition build 17744, the ReleaseId field shows 1809.

So something like this should do the trick:

const auto isWinServer2019Plus =
  IsWindowsServer() &&
  IsWindowsVersionOrGreater(10, 0, 1803);
like image 177
NuSkooler Avatar answered Sep 18 '22 21:09

NuSkooler


Apart from checking MajorVersion, MinorVersion and ProductType you also have to check the ReleaseId or BuildNumber.

ReleaseId: 1809 and BuildNumber: 17763 are associated with the release versions of Windows Server 2019 and Windows Server, version 1809. So by checking for those numbers you should at least be sure that you're either dealing with Windows Server 2019 or Windows Server, version 1809 (Semi-Annual Channel) (Datacenter Core, Standard Core).

enter image description here

See: Windows Server release information

Note: Insider Preview builds of Windows Server 2019 can have ReleaseId 1803 or BuildNumbers below 17763.


In this thread Mary Hoffman from Microsoft says:

ReleaseId

1809 is associated with Windows Server 2019 and Windows Server, version 1809 only. (post)

Windows Server 2016 will always be 1607. Once a product is released, that ID will not change. (post)

Following that logic Windows Server 2019 will also always be 1809.

You can read the ReleaseId from this registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion - ReleaseId

See: How to read a value from the Windows registry

BuildNumber

Windows Server 2019 stops at 17763. That was the final major build number.

Anything higher than that (>=17764) will be vNext builds. (post)

Windows Server 2016 will always be 10.0.14393.### where ### increments as cumulative updates are installed.

Windows Server 2019 will always be 10.0.17763.### where ### increments as cumulative updates are installed. (post)

So BuildNumber 17763 should always correspond to Window Server 2019 or Windows Server, version 1809 (or Windows 10 1809, but checking ProductType tells you if its a server).

like image 24
frido Avatar answered Sep 20 '22 21:09

frido