title: C++ How to detect Windows Server 2019?
body: <p>Microsoft released Windows Server 2019 on October 2, 2018. From Windows 2000 and up until this Windows version, you could call a WinAPI function <a href="https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getversionexa" rel="noreferrer">GetVersionEx</a> with a struct <a href="https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_osversioninfoexa" rel="noreferrer">OSVERSIONINFOEX</a> and depending on the variables of <code>dwMajorVersion</code>, <code>dwMinorVersion</code> and <code>wProductType</code> determine Windows version, for example, Windows 8.1, Windows 10, Windows Server 2012 R2. The code everyone used was something like this:</p>
  
  <pre><code>OSVERSIONINFOEX osvi;
  SecureZeroMemory(&amp;osvi, sizeof(OSVERSIONINFOEX));
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  if (GetVersionEx(&amp;osvi)) {
      if (osvi.dwMajorVersion == 10 &amp;&amp;
          osvi.dwMinorVersion == 0 &amp;&amp;
          osvi.wProductType != VER_NT_WORKSTATION) {
              Console-&gt;Log("We are running on Windows Server 2016");
          }
  }
  </code></pre>
  
  <p>Judging from <a href="https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions" rel="noreferrer">Wikipedia</a> the Windows Server 2019 has the same version number of NT 10.0 as Server 2016. So the above code does not work anymore.</p>
  
  <p>Also, Microsoft Docs contains the following note: <em>GetVersionEx may be altered or unavailable for releases after Windows 8.1. Instead, use the Version Helper functions.</em></p>
  
  <p>Unfortunately, the <a href="https://docs.microsoft.com/en-us/windows/desktop/SysInfo/version-helper-apis" rel="noreferrer">Version Helper functions</a> does not have a function to detect Server 2019. Also, the strange thing is that Docs page about <a href="https://docs.microsoft.com/en-us/windows/desktop/SysInfo/targeting-your-application-at-windows-8-1" rel="noreferrer">Targeting</a> 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.</p>
  
  <p><strong>Update 1.</strong>
  As @IInspectable and @RbMm commented about usage of <code>RtlGetVersion</code> function. So I ran the following code (taken from <a href="https://stackoverflow.com/a/36545162/220425">this answer</a>):</p>
  
  <pre><code>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(&amp;rovi) ) {
                  return rovi;
              }
          }
      }
      RTL_OSVERSIONINFOW rovi = { 0 };
      return rovi;
  }
  </code></pre>
  
  <p>And here are the results for <strong>Windows 10:</strong></p>
  
  <ul>
  <li><strong>dwMajorVersion = 10</strong></li>
  <li><strong>dwMinorVersion = 0</strong></li>
  <li>dwBuildNumber = 17134</li>
  <li>dwPlatformId = 2</li>
  </ul>
  
  <p><strong>Windows Server 2019:</strong></p>
  
  <ul>
  <li><strong>dwMajorVersion = 10</strong></li>
  <li><strong>dwMinorVersion = 0</strong></li>
  <li>dwBuildNumber = 17763</li>
  <li>dwPlatformId = 2</li>
  </ul>
  
  <p><strong>Update2.</strong> As requested, posting full info from <strong>OSVERSIONINFOEX</strong> struct that was obtained via <strong>GetVersionEx</strong> call with a manifest file containing all the Targets till Windows 10 (see the Targeting link above):</p>
  
  <pre><code>// 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
  </code></pre>
  
  <p><strong>Update 3.</strong> Calling <code>RtlGetVersion</code> with a struct <code>RTL_OSVERSIONINFOEXW</code> we get exactly the same result as in Update 2.</p>