0

What is the correct way of getting the Windows version (more or less what the now deprecated GetVersionEx does, but without lying).

Please don't tell me that I shouldn't use version checking, or that I should use VerifyVersionInfo. It's not for version checking but for generating a report. And it should also work in future versions of Windows (e.g Windows 11 or whatever)

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/169095/discussion-on-question-by-michael-walz-correct-way-of-getting-windows-version). – Andy Apr 16 '18 at 15:16
  • There are tons of questions on StackOverflow, and many duplicates, about how to get the true OS version without using `GetVersionEx()`. Please do some research before asking new questions. For example, [this answer](https://stackoverflow.com/a/39173324/65863) – Remy Lebeau Apr 16 '18 at 15:25
  • @RichardCritten yes, but that's not what I need (the title _Getting the System Version_ is somewhat misleading, this doesn't work for future WIndows versions, only for known Windows versions). There are ~25 comments which have been move to chat (see first comment above). – Jabberwocky Apr 16 '18 at 15:30

1 Answers1

2

If you need a real Windows version with build number that is not virtualized regarding your app.manifest file you can get a Windows kernel version from ntoskrnl.exe:

std::string GetNtDllVersion()
  {
    std::string versionString;
    DWORD someHandle;
    wchar_t systemFolderPath[ _MAX_PATH + 1 ];
    UINT systemFolderPathSize = GetSystemDirectory( systemFolderPath, _MAX_PATH );
    if ( systemFolderPathSize > 0 )
    {
      std::wstring ntDllPath( systemFolderPath, systemFolderPathSize );
      ntDllPath += L"\\ntoskrnl.exe";
      DWORD versionSize = GetFileVersionInfoSize( ntDllPath.c_str(), &someHandle );
      if ( versionSize > 0 )
      {
        LPVOID dataPtr = malloc( versionSize );
        if ( dataPtr != NULL )
        {
          if ( GetFileVersionInfo( ntDllPath.c_str(), 0, versionSize, dataPtr ))
          {
            UINT length;
            LPVOID outputPtr;
            if ( VerQueryValue( dataPtr, L"\\", &outputPtr, &length ))
            {
              VS_FIXEDFILEINFO* versionStructPtr = ( VS_FIXEDFILEINFO* )outputPtr;
              if ( versionStructPtr->dwSignature == 0xFEEF04BD )
              {
                versionString = std::to_string( HIWORD( versionStructPtr->dwFileVersionMS ));
                versionString += ".";
                versionString += std::to_string( LOWORD( versionStructPtr->dwFileVersionMS ));
                versionString += ".";
                versionString += std::to_string( HIWORD( versionStructPtr->dwFileVersionLS ));
                versionString += ".";
                versionString += std::to_string( LOWORD( versionStructPtr->dwFileVersionLS ));
              }
            }
          }
          free( dataPtr );
        }
      }
    }
    return versionString;
  }
crea7or
  • 4,421
  • 2
  • 26
  • 37
  • This looks like one of the good options... – Jabberwocky Apr 16 '18 at 16:20
  • if you'll launch `winver.exe` you'll see the same windows version as `ntoskrnl.exe` – crea7or Apr 16 '18 at 16:24
  • 3
    Although this is how Microsoft *suggests* solving this problem, it is not the simplest solution. Using [`RtlGetVersion()`](https://msdn.microsoft.com/en-us/library/mt723418.aspx), [`NetServerGetInfo()`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa370624.aspx), or [`NetWkstaGetInfo()`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa370663.aspx) would work just as well, and require much less coding. – Remy Lebeau Apr 16 '18 at 17:43
  • 1
    and if you run this code you can got 6.2 version on windows 10. this nothing solve - [*You are reading the wrong fields from the version information for this task. Instead of dwFileVersionMS and dwFileVersionLS use dwProductVersionMS and dwProductVersionLS*](https://stackoverflow.com/a/38069323/6401656) – RbMm Apr 16 '18 at 19:02
  • @RbMm challenge accepted. [Source of win32 app](https://github.com/crea7or/getwindowsversion) that only show the version in MessageBox with the supplied code. Does work well in Windows 8.1 - 10. No embeded manifest and build with Windows XP compiler tools of VS2012. – crea7or Apr 16 '18 at 20:36
  • @crea7or - in windows 10, this code give me 6.2 if use `dwFileVersionMS`. if use `dwProductVersionMS` - 10.0. and anyway - why not simply use documented for user mode api `RtlGetVersion` ? – RbMm Apr 16 '18 at 20:59
  • I just run your exe - it really show 10.0, however my test code - 6.2 - I now look, why/where different – RbMm Apr 16 '18 at 21:18
  • 1
    ok, your error that you use `ntoskrnl.exe` - in 64bit system it exist in `system32` folder but not in `syswow64`. and your app is 32 bit - where active fs-redirector. say we got path `c:\windows\system32\ntoskrnl.exe` - but it redirected to `c:\windows\syswow64\ntoskrnl.exe` - this file simply not exist. but `GetFileVersionInfo` silently try `system32` folder too. but in critical place - [`IsFileOwnedByTrustedInstaller`](https://i.stack.imgur.com/tDeuy.png) called - it return false for 32bit app in 64bit system. otherwise we go to 6.2 version fix – RbMm Apr 16 '18 at 21:38
  • anyway use `ntoskrnl.exe` which is exist only in `system32` but not in `syswow64` - this is by fact *UB*. build your app as 64 bit - and you got 6.2, when 32bit got 10.0. or change `ntoskrnl.exe` to say `ntdll.dll` or `kernel32.dll` (both this dlls exist in both places) and you again got 6.2 version. of course possible use `dwProductVersionMS` or get version info yourself without use api `GetFileVersionInfo`.. anyway I be not say that this is more reliable way compare use ntdll api – RbMm Apr 16 '18 at 22:06