Getting OS build version from Win32 Api C++

10,092

Option 0: (per RbMm) Use [RtlGetVersion] from the driver development kit.

Option 1: [Updated] Grab the version number of a system DLL like kernel32.dll. MSDN used to bless this approach, saying:

To obtain the full version number for the operating system, call the GetFileVersionInfo function on one of the system DLLs, such as Kernel32.dll, then call VerQueryValue to obtain the \StringFileInfo\\ProductVersion subblock of the file version information. [From an Internet Archive snapshot of MSDN circa 2017]

That would look something like this:

// Quick hack without error checking.
#include <cassert>
#include <iomanip>
#include <iostream>
#include <vector>
#include <Windows.h>

int main() {
  const auto system = L"kernel32.dll";
  DWORD dummy;
  const auto cbInfo =
      ::GetFileVersionInfoSizeExW(FILE_VER_GET_NEUTRAL, system, &dummy);
  std::vector<char> buffer(cbInfo);
  ::GetFileVersionInfoExW(FILE_VER_GET_NEUTRAL, system, dummy,
                          buffer.size(), &buffer[0]);
  void *p = nullptr;
  UINT size = 0;
  ::VerQueryValueW(buffer.data(), L"\\", &p, &size);
  assert(size >= sizeof(VS_FIXEDFILEINFO));
  assert(p != nullptr);
  auto pFixed = static_cast<const VS_FIXEDFILEINFO *>(p);
  std::cout << HIWORD(pFixed->dwFileVersionMS) << '.'
            << LOWORD(pFixed->dwFileVersionMS) << '.'
            << HIWORD(pFixed->dwFileVersionLS) << '.'
            << LOWORD(pFixed->dwFileVersionLS) << '\n';

  return 0;
}

Note that the original MSDN link now redirects to a newer documentation set that doesn't mention this approach. I suppose that means this is no longer a supported technique, and, presumably, all the compatibility hacks for older code might prevent an application from getting the actual answer.

Option 2: Query the registry, specifically:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

which has values for CurrentMajorVersionNumber, CurrentMinorVersionNumber, and CurrentBuildNumber.

I can't find official documentation for these values, so this may not be MSDN-approved or future-proof.

Option 3: Use GetProductInfo if available and fall back to GetVersionInfo if it's not.

Share:
10,092
anon
Author by

anon

Updated on June 18, 2022

Comments

  • anon
    anon almost 2 years

    I am trying to find the build version of Windows Server 2016 machines, for example RS1 or RS3. There was an API to do this - GetVersionEx() - but is now deprecated.

    MSDN says to use Version Helper Functions instead.

    I want the build version, for ex: 1607 for RS1.

    Is there an API to get this?

    • David Heffernan
      David Heffernan over 6 years
      Use the version helper functions
    • anon
      anon over 6 years
      Is there a way to get the version or not? If not why is that not clearly stated anywhere? Like I said I don't want the helper version stuff. How am I suppose to differentiate between the WS 2016 RS1 and RS3 image.
    • Richard Chambers
      Richard Chambers over 6 years
    • anon
      anon over 6 years
      Already looked at that. IsWindowsServer() doesn't solve my problem.
    • Richard Chambers
      Richard Chambers over 6 years
      From Targeting your application for Windows there is this function VerifyVersionInfo function though in "Windows 10, the VerifyVersionInfo function has also been deprecated."
    • Remy Lebeau
      Remy Lebeau over 6 years
      The version helper functions dont return the actual version number, like GetVersion/Ex() does. They compare the version number to a requested version and return the result of the comparison. To learn the exact version number, you would have to make several comparisons, which is tedious.
    • Remy Lebeau
      Remy Lebeau over 6 years
      If you need to discover the exact version number, you can use RtlGetVersion(), NetServerGetInfo() or NetWkstaGetInfo(), which are not deprecated or subject to manifestation (yet?). Or, do what MSDN suggests.
    • Mike Vine
      Mike Vine over 6 years
      This seems like an X/Y problem. What do you want the version number for?
    • anon
      anon over 6 years
      RtlGetVersion works for me. Loaded the ntdll.dll and got the RtlGetVersion. %HMODULE ntDll = GetModuleHandleW(L"ntdll.dll"); rtlGetVersion getVersion = (rtlGetVersion)GetProcAddress(ntDll, "RtlGetVersion"); %
  • RbMm
    RbMm over 6 years
    why not use option 0 - call RtlGetVersion or undocumented RtlGetNtVersionNumbers. anyway this more simply and fast compare this way
  • zett42
    zett42 over 6 years
    @RbMm So RtlGetVersion does not lie like GetVersionEx if you don't have the latest Compatibility entries in manifest?
  • RbMm
    RbMm over 6 years
    @zett42 - no, RtlGetVersion until always return true windows version, and not look for manifest
  • RbMm
    RbMm over 6 years
    @zett42 - however the latest build windows number, where i look this is 15063 (and here RtlGetVersion still read correct values from PEB), not look more resent builds. interesting link, but no more resent build under hand now
  • Anders
    Anders over 6 years
    @RbMm I think RtlGetVersion is affected by the compatibility tab settings on a .exe.
  • RbMm
    RbMm over 6 years
    @Anders - you can look binary code of RtlGetVersion (under debugger or disassembler) - it enough simply - unconditionally read this values from process PEB . however i not view the latest build, but on 15063 stil true version
  • Anders
    Anders over 6 years
    @RbMm And who fills the PEB (You can mess with the PE file to set some of these values)? Anyway, looking at the code is pointless because those functions get hooked by aclayers.dll.
  • RbMm
    RbMm over 6 years
    @Anders yes :) you was correct. the RtlGetVersion is hooked by aclayer.dll and return "compatible" version. but RtlGetNtVersionNumbers not hooked and return correct version number. in the process PEB also real values
  • Anders
    Anders over 6 years
    @RbMm But you can hex-edit the PE file so that those PEB fields have whatever number you want. I'm sure it is only a matter of time until RtlGetNtVersionNumbers is hooked as well.
  • RbMm
    RbMm over 6 years
    @Anders - no, PEB this is not part of pe file but semi-documented structure in memory (process environment block) - allocated by kernel in process creation time. think here always must be correct values, which need for internal system work. are RtlGetNtVersionNumbers will be hooked - don't know. may be yes. interesting that before win10 this function simply return values hard-coded in ntdll.dll. now (win 10) it read it from peb
  • Anders
    Anders over 6 years
    @RbMM I know perfectly well what the PEB is. The PEB can be filled with values from the PE file if you tweak it correctly.
  • RbMm
    RbMm over 6 years
    @Anders - what you mean ? that ntdll or shim under some case can read major/minor values from exe optionalheader and write it to peb ?
  • Anders
    Anders over 6 years
    @RbMm IMAGE_LOAD_CONFIG_DIRECTORY::CSDVersion (if not zero) is written to the PEB etc. I assume it is ntdll that does it when you create the process. The major/minor version PE fields are somewhere else and not documented AFAIK.
  • RbMm
    RbMm over 6 years
    @Anders - dont know. even if use not 0 MajorVersion, MinorVersion, CSDVersion i view under peb real os values. however may be i not set some flags/etc. not research this early, but until not view visible effect from play with IMAGE_LOAD_CONFIG_DIRECTORY in this direction. however this already some offtopic for original question - the IMAGE_LOAD_CONFIG_DIRECTORY control who build of exe. if it patched.. but any code can be patched.
  • Charles Oppermann
    Charles Oppermann over 4 years
    " MSDN blesses this approach" I don't see anything on the linked page that discusses using the build number of kernel32.dll as being "blessed" or otherwise endorsed. Maybe it was previously discussed, but not as of this writing. I've had cases where the build number of kernel32.dll was different from what's reported via winver.exe.
  • Adrian McCarthy
    Adrian McCarthy over 4 years
    @CharlesOppermann: The MSDN link is now redirected to Microsoft's newer documentation set, and the newer version doesn't have it. I'll update the answer with the relevant bit as captured by the Wayback Machine.
  • ceztko
    ceztko over 3 years
    Great there's RtlGetVersion! Requiring installing DDK just for one function may be overkill, though. Can you integrate the answer pointing to this gist that has just the useful declarations?