How do I detect Windows 10 if I cannot GetProcAddress for the function IsWindows10OrGreater?


A customer wanted to use the handy functions provided in the Version­Helpers.h header file, like Is­Windows­10­Or­Greater, while maintaining the same source code for both Windows 7 and Windows 10 targets. Their plan was to Load­Library for kernel32.dll, and then Get­Proc­Address for Is­Windows­10­Or­Greater, but they found that the Get­Proc­Address call always failed, even on Windows 10. They looked in kernelbase.dll and ntdll.dll; no luck there either. How is it possible that Windows 10 doesn't know whether it is Windows 10?

The customer investigated further and found that when their test program called Is­Windows­10­Or­Greater, there was no call to Load­Library at all!

0:000> k
# ChildEBP RetAddr  
00 0133f9fc 00c01806 ntdll!VerSetConditionMask+0x14
01 0133fc2c 00c01739 Test!IsWindowsVersionOrGreater+0xa6 
02 0133fd0c 00c01a33 Test!IsWindows10OrGreater+0x29
03 0133fe10 00c022be Test!main+0x23
04 0133fe24 00c02120 Test!invoke_main+0x1e
05 0133fe7c 00c01fbd Test!__scrt_common_main_seh+0x150
06 0133fe84 00c022d8 Test!__scrt_common_main+0xd
07 0133fe8c 77a962c4 Test!mainCRTStartup+0x8
08 0133fea0 77bd0609 KERNEL32!BaseThreadInitThunk+0x24
09 0133fee8 77bd05d4 ntdll!__RtlUserThreadStart+0x2f
0a 0133fef8 00000000 ntdll!_RtlUserThreadStart+0x1b

The customer wanted to know how to call functions like Is­Windows­10­Or­Greater dynamically.

The reason the customer cannot find the function Is­Windows­10­Or­Greater in kernel32.dll or any other DLL is simple: The function was inside you all along.

The functions in the Version­Helpers.h header file are all inline functions. They are not exported anywhere. These functions do the grunt work of figuring out the operating system so you don't have to write the version detection code yourself (and invariable mess up) by building the appropriate query and calling Verify­Version­Info, which has been available since Windows 2000 (possibly longer).

If you think about it, the answer must be like that, for how could kernel32.dll export all of these specific version-checking functions? The Windows 7 version of kernel32.dll would have to be clairvoyant and have exports for all of these functions like Is­Windows­10­Or­Greater, which would be quite a feat. Presumably the implementations would simply be hard-coded to return either TRUE or FALSE, as appropriate. (I guess you could imagine that each version of Windows exports only the functions for which it returns TRUE, and the absence of the function implies that the corresponding version is not installed.)

So just go ahead and use the functions in Version­Helpers.h. They will always work and give you an answer. (Well, unless you're targeting systems earlier than Windows 2000, but if you're doing that, then you probably aren't too interested in version detection since your customer that is still running Windows NT 4.0 is unlikely ever to upgrade.)

Bonus chatter: Note that the operating system version check does raise its own question: "Why are you doing an operating system version check at all?" Because that sort of thing gives the application compatibility team the heebie-jeebies. We asked, but the customer never did answer that question.

Comments (44)
  1. Mike Diack says:

    A “unapproved” Quick and dirty version is to use RtlGetVersion (which is only ever lied to, if the customer has explicitly shimmed the application). (Waits for Raymond to slap me!). Note Windows versions earlier than 2000 don’t have RtlGetVersion, so there’ll you need to use GetVersionEx…..

    1. Incorrect. RtlGetVersion is present in NT 4 (at least), GetVersionEx is just a simple wrapper around it…

  2. Brian_EE says:

    >”Why are you doing an operating system version check at all?”

    Are you suggesting that Windows 10 had no new APIs since, say, Windows 7? Or that developers shouldn’t take advantage of new APIs and OS features when they can?

    1. Boris says:

      1) What if whatever you’re looking for is later backported to Windows 7?
      2) What if whatever you’re looking for disappears in a later update to Windows 10?

      1. Darran Rowe says:

        For 2, this is your own fault.
        The type of function that can vanish in later versions of Windows are explicitly documented as such.
        Functionality normally has support that lasts a really long time. As an example, the original registry functions are still exported for backwards compatibility.

      2. Brian_EE says:

        1) Presumably you’ve provided an alternate (maybe less efficient/fast/optimized) way to handle the function on older systems that lack the new feature. Your code isn’t broken, and you can always update your app if you desire (or your customer base has sufficient leverage).

        2) That is always a risk no matter what system you are on. But if MS is actively promoting these new APIs, you should be able to make some reasonable assumptions about availability.

        1. Wear says:

          The point is you should be checking for features no versions.

          You want to know “Can I do this?” so ask “Can I do this?” not “Are you one of the things that I know can do this?”

          1. Boris says:

            Yes. Brian’s and Darren’s comments both apply, but if Brian’s goal is to take advantage of specific features (and, of course, provide substitutes if they’re unavailable), then the check must be made for the feature, not for the version number.

          2. Zenith says:

            Telling people to check for features is as useless as telling people to make a business plan. Because the question that immediately follows (“how?”) is answered with “lol idunno” if at all. Beyond Kernel32’s IsProcessorFeaturePresent(), what other feature checks are there? We can’t even check for the presence of certain applications because the Programs list is full of arbitrary information written by installers themselves. That’s why we’re so often forced to fall back on version checks like this.

          3. If you want to know if a function exists, then use GetProcAddress. If you want to know whether a COM interface exists, use QueryInterface.

          4. Zenith says:

            And if the function acts differently or supports different flags in different versions?

          5. Harald van Dijk says:

            To deal with functions that work differently across OS versions, simply call them and see what happens. If a flag was added to Windows 10 that didn’t exist in earlier versions: if the flag gets ignored, detect that the call gives a “wrong” result. If the function will return an error code saying the flag is invalid, that’s even easier to detect.

  3. Darran Rowe says:

    ‘Note that the operating system version check does raise its own question: “Why are you doing an operating system version check at all?”‘
    This depends on the situation, if there was a feature added to a version and never backported, like UMS or some of the features added to Direct3D/Direct2D in 8.1, then it is often easier but just as accurate to just check before hand. You can then use this to make the code neater in some cases without having conditionals everywhere.
    Of course, I understand that for the D3D case it is also possible just create the D3D device and then query for ID3D11Device2.

  4. Medinoc says:

    For some time I imagined it could be possible to create a system for stubs in import libraries which, according to, say, flags on the .def file, would return different values/error conditions if the function isn’t found (some flag would mean “return E_NOTIMPL”, some “always TRUE”, “always FALSE”, etc.; plus a flag on whether to call SetLastError() with ERROR_SUCCESS, ERROR_NOT_IMPLEMENTED or not at all).

    Bonus chatter: I’ve put a check for Windows Vista in my code, in order to know whether my program could use task dialogs for some choices or should roll its own instead. And since it was a C# program, I actually translated the code of IsWindowsVistaOrGreater() for that.

    1. Ben Voigt (Visual Studio and Development Technologies MVP with C++ focus) says:

      You basically want delay-loading to resolve to an application-provided fallback function if one is provided, and call the delay-load error handler only if resolution fails and no fallback is provided?

      A good idea, but not quite so easy, because the delay-load error handling scheme has the opportunity to say “look in a DLL found in this other path for those functions instead”. Should that handler still run if there’s a fallback?

      I’m sure all the details could be worked out eventually.

  5. DWalker07 says:

    Is there a function named “IsWindows10OrGreater” in the Windows 7 codebase? I would not expect such a thing! How can they use the same codebase then?

    1. Erik says:

      A guessplanation:
      – IsWindows10OrGreater does not ‘exist in Windows’, not even in Windows 10, but in the source code you get “for free” with Visual Studio and other development environments.
      – IsWindows10OrGreater internally calls Verify­Version­Info, a function that exists in all Windowses we care about.
      – When compiling, the name IsWindows10OrGreater is replaced by a direct call to Verify­Version­Info. The program distributed to the users therefore contains no reference to IsWindows10OrGreater, but rather something like ‘if (getVersion() >= 10)’ (actually, not 10, but let’s not make things as complicated as they are).

      1. DWalker07 says:

        Thanks….

  6. skSdnW says:

    Verify­Version­Info was added in a NT 4 service pack but the implementation is buggy and slightly different from later versions.

  7. Uranium says:

    > “Why are you doing an operating system version check at all?”

    Well… This is a bit of a stretch, but one reason might be to find out what the actual meaning of WTS_SESSIONSTATE_LOCK/WTS_SESSIONSTATE_UNLOCK is on the OS. On Windows 7 the meaning is reversed: https://msdn.microsoft.com/en-us/library/ee621019(v=vs.85).aspx

  8. Kevin says:

    > “Why are you doing an operating system version check at all?”

    Maybe you’re writing one of those “Win+Pause isn’t fancy enough for me” applications (i.e. a program that tells you various things about your computer including the OS version). In that case, though, you probably just want a human-readable string instead of an “Are we Windows 10 yet?” boolean.

    1. Richard says:

      Indeed. What exactly are we supposed to do when trying to collect metrics about which OS versions our users are using?
      For example, how do we decide when we can drop support for Windows XP?

      Aside from that, when a customer calls us and says “X doesn’t work right”, one of the rather useful things to know is what version of Windows they are running. Can’t ask them, they don’t understand the question.
      – Perhaps I made a mistake in feature checking and try to use a feature that definitely can’t exist in Win 8.0. Logging the result of my broken feature check is never going to find that bug.

      So, what’s the replacement for GetVersion? I have not been able to find that in MSDN.

      1. Telemetry is a good reason to get the version. But that’s not the same as using the version to alter program behavior. That’s why we asked what the customer was using the function for. And if you wanted it for telemetry purposes, you wouldn’t use IsWindows10OrGreater anyway.

        1. Marco Burato says:

          So, what is one supposed to do in this case? Last time I checked, GetVersion lies on Windows 10 (why?).

          1. Joshua says:

            I report the exact version number of kernel32.dll

          2. Paul says:

            Because, as far as I can tell, the app isn’t manifested for Win10

      2. Mike Diack says:

        See my original post, you can use RtlGetVersion on Windows 2000 and later to get the OS version, which is always accurate and true (even on Windows 10, unless the user has actively shimmed (e.g. via Application Compatibility Toolkit)) even for all Windows 10 builds. This is what I’ve used in my own apps to dump/log version details for bug reporting details / logging details etc.

    2. Brian_EE says:

      Win+Pause – you learn something new everyday…

      1. pc says:

        I always knew it as “Win+Break”, though I’m not sure why as the key is certainly known as Pause when unshifted. Maybe just because it’s funny to think of “Windows Breaking” or the like.

        I think I must have learned it as that from some documentation somewhere in Windows’s built-in help. The first KB article I found on Windows shortcut keys (https://support.microsoft.com/en-us/help/126449/keyboard-shortcuts-for-windows) calls it “Windows Logo+Break”.

  9. Myria says:

    A problem with VersionHelpers.h is that you still can’t detect Windows 10 if you don’t have the Windows 10 GUID in your manifest. We’ve had to use RtlGetVersion, carefully, because of this problem. We are scared to use the Windows 10 GUID in the manifest because it could change the behavior of some function in the API and subtly break our decade-old product.

    1. Medinoc says:

      Then you “half-support” Windows 10? Like, you want your program to reap some benefits of Windows 10 when present, but without actually supporting Windows 10?

  10. Drak says:

    We get the version of the OS to see if we support it. Our product may work on your OS, but if we don’t support your OS you cannot ask us for free help with problems. We like to tell the customer this in advance, so they know what to expect.

  11. Chris Crowther says:

    The only reason we ever want to know what the OS and service pack level are is so that we can put it in a log file, because support like to know what the client actually has (because our clients never do). Which mostly means I just want a string. Preferably an unlocalised one.

  12. xcomcmdr says:

    Once I had to know which OS version I’m running, in order to use DXWND (third-party software that hooks into processes and modify their behavior and environment), so an old game (Total Annihilation) would have true fullscreen under Windows 8 and higher.

    It wasn’t needed (even harmful) to use DXWND for this game on Windows 7 and lower, so that’s why I had to use OSVersion (nuget package) to know how to launch the game.

    What gives me the heebie-jeebies is that a lot of old games have a broken fullscreen mode since Windows 8 (that is the game is in fullscreen, but you can still see the window chrome around it as long as the game runs. And of course the game doesn’t use all the screen anymore.). If that’s broken, what else is or wlll break ?

    Windows 9X emulator are still very limited (namely DOSBox-X and PCem), so that’s why I’m using wrappers such as DDRawCompat or dgVoodoo or nGlide, and/or DXWND, and/or compatibilty options, but sometimes I wonder if all that will be for naugh once Windows 10 Update + 1 lands…

    I wonder what change in DWM broke all those Direct3D 5/6/7 games… (non-full list : Resident Evil 2, Drakan, Dino Crisis, Metal Gear Solid, Total Annihilation, Hogs of War, …)

    1. xcomcmdr says:

      s/OSVersion/OSInfo, my bad.

    2. Chris says:

      Huh, I didn’t know that. That’s actually kind of funny, because I had the exact opposite experience with another legacy game: Diablo 2. It required all kinds of annoying tweaking to get D2 to work in Windows 7. It worked out of the box for me in Windows 8.

  13. David Haim says:

    Why are you doing an operating system version check at all?”

    well that’s a question I did not expected from Raymond..
    If we won’t check the OS version because it’s the “idomatic” thing to do, we’ll be limiting ourselves to the lowest common API available, which these days is XP. so no SRW locks, Condition Variables, non-crappy threadpool and pretty much everything which was introduced in windows vista.

    you want to use the latest features your OS provides. sometimes it requires to check the OS version and make the program take strategy based on that.

    1. SimonRev says:

      I would argue in 2017, the lowest common API would be Windows 7 not Windows XP. I know marketing screamed when R&D pulled the plug on XP support two years ago on our main product and it turns out exactly nobody cared.

      However, Raymond isn’t saying don’t use the API functions introduced in Windows 8/10 if they are available, the point is that you DON’T use an OS version check to determine if the API is available. If you are using the Windows 7 lowest common denominator but want to optionally use higher version API’s if available, you are going to be doing stuff like LoadLibrary/GetProcAddress anyway, for which you will have to write error handling code. Just use the error handling code there and don’t worry about the actual OS version.

    2. voo says:

      That’s not how you’re supposed to do this. If you want to know if you can use some feature, ask for that feature.

  14. Neil says:

    Sometimes I just want to report the operating system version my customer is using, for diagnostics or analytics. Which is a lot harder to do now, thanks to the app compat team having heebie-jeebies and adding manifest-base behavior. Requiring my older software versions to be clairvoyant with its manifest declarations, or to use more annoying methods of retrieving the real OS version…

    1. John Styles says:

      Yes indeed. Surely this is the obvious and a perfectly reasonable use case?

    2. Mark Ransom says:

      Too bad this forum doesn’t have a +1 button. Consider this declaration of support my +1.

  15. Mark Ransom says:

    Does anybody remember why there’s no Windows 9? It’s because too many programs did a version check and failed when the version started with ‘9’, assuming it was Windows 95 or Windows 98.

    1. xcomcmdr says:

      That’s only a rumor.

Comments are closed.

Skip to main content