1

I have seen in a few questions/answers on how to detect the OS version of Win 8.1 and 10.0 using VerifyVersionInfo (since GetVersionEx no longer works without manifesting), but this only allows me to check if the OS is a version you pass to the function. It does not return this info to me. For example, with GetVersionEx it would tell me the major, minor, and build versions, but with VerifyVersionInfo I have to essentially ask "Is the OS version 6.3 or greater?" or "Is the OS version 10.0 or greater?" since GetVersionEx now returns 6.2 for the OS version even if it is actually 6.3 or 10.0.

This is fine in that I can easily add this check to my code, but I now have no way of getting the build version since VerifyVersionInfo does not tell me this. Is it possible to still get the build version by some other means?

Here is what I am doing now to determine if the OS is 8.1 or 10.0:

function IsWindowsVersionOrGreater(wMajorVersion, wMinorVersion, wServicePackMajor: Word): Boolean;
var
  osvi: OSVersionInfoEX;
  dwlConditionMask: Int64;
begin
  FillChar(osvi, sizeof(osvi), 0);
  osvi.dwOSVersionInfoSize := SizeOf(osvi);
  osvi.dwMajorVersion := wMajorVersion;
  osvi.dwMinorVersion := wMinorVersion;
  osvi.wServicePackMajor := wServicePackMajor;
  dwlConditionMask := VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
  dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
  dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
  Result := VerifyVersionInfo(osvi, VER_MAJORVERSION or VER_MINORVERSION or VER_SERVICEPACKMAJOR, dwlConditionMask);
end;

function IsWindows8Point1OrGreater: Boolean;
begin
  Result := IsWindowsVersionOrGreater(HIBYTE(WIN32_WINNT_WINBLUE), LOBYTE(WIN32_WINNT_WINBLUE), 0);
end;

function IsWindows10OrGreater: Boolean;
begin
  Result := IsWindowsVersionOrGreater(HIBYTE(WIN32_WINNT_WIN10), LOBYTE(WIN32_WINNT_WIN10), 0);
end;

function GetWinVersion: string;
var
  osVerInfo: TOSVersionInfo;
  majorVersion, minorVersion: Integer;
begin
  Result := '?.?';
  osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo) ;
  if GetVersionEx(osVerInfo) then
  begin
    minorVersion := osVerInfo.dwMinorVersion;
    majorVersion := osVerInfo.dwMajorVersion;

    if (majorVersion = 6) and (minorVersion = 2) then
    begin
      if IsWindows10OrGreater() then              // 8.1+ does not report correct version.
        Result := '10.0'                          // NOTE: NO BUILD NUMBER
      else if IsWindows8Point1OrGreater() then
        Result := '6.3'
      else                                        // This 6.2 is actually Win 8
        result:=inttostr(majorVersion)+'.'+inttostr(minorVersion)+'.'+inttostr(osVerInfo.dwBuildNumber);
    end
    else
      result:=inttostr(majorVersion)+'.'+inttostr(minorVersion)+'.'+inttostr(osVerInfo.dwBuildNumber);
    end;
 end;

EDIT: As suggested by David, the solution was to use WMI. This works with Win 8.1 and Win 10 and does not need you to keep an updated manifest with each new version of Windows.

function  GetWinVersion8AndUp(): String;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  Result := '';

  try
  try
    FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
    FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
    FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
    oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
    while oEnum.Next(1, FWbemObject, iValue) = 0 do
    begin
      Result := Format('%s',[String(FWbemObject.Version)]);

      FWbemObject:=Unassigned;
    end;
  except
  end;
  finally
  end;
end;
Evan Zimmerman
  • 333
  • 1
  • 4
  • 16
  • Personally I'd consider WMI – David Heffernan Jul 31 '15 at 18:57
  • 3
    The official recommendation is: don't do version checks. There is a *reason* that ``GetVersionEx`` is deprecated in Windows 8.1, and those reasons are why ``VerifyVersionInfo`` is also deprecated in Windows 10. What you are doing is writing a lot of code that is just going to create appcompat problems, and there's really very little point since as of Windows 10 and the continuous update policy it's all meaningless anyhow. – Chuck Walbourn Jul 31 '15 at 19:01
  • **So, the question is:** What are you trying to actually do here? In most cases, a version check is a poor substitute for doing some more direct test but it's very domain specific. There are usually built-in ways to determine if a feature is present through COM creation, or explicit linking, etc. These are all far more robust than finicky error-prone version check assumptions. – Chuck Walbourn Jul 31 '15 at 19:04
  • The "good" use for ``VeriyVersionInfo`` is for 'you must be this high to ride this ride' style checks which is what ``VersionHelpers.h`` does. The issue is that with Windows 10 if you do not have a manifest with the Windows 10 GUID, you get a conservative/wrong answer for ``IsWindows8Point1OrGreater`` or ``IsWindows10OrGreater ``. Practically, however, when do you write a Windows desktop app that works only on Windows 8.1+ or Windows 10+? See [this blog post](http://blogs.msdn.com/b/chuckw/archive/2010/02/24/what-s-in-a-version-number.aspx) – Chuck Walbourn Jul 31 '15 at 19:04
  • `VerifyVersionInfo` deprecated in Win 10. Didn't know that. You got any links to more info? – David Heffernan Jul 31 '15 at 19:08
  • The main thing developers seem to be doing is create support telemetry. In this case, ideally you just add the manifest elements to your app and call ``GetVersionEx`` for the sole purpose of creating a string to go in a log file or a support email. Don't do any code checks with it at all. See [this blog post](http://blogs.msdn.com/b/chuckw/archive/2013/09/10/manifest-madness.aspx). For universal Windows apps in Windows 10, there is a new [WinRT API](https://msdn.microsoft.com/en-us/library/windows/apps/windows.system.profile.analyticsinfo.versioninfo) for this purpose. – Chuck Walbourn Jul 31 '15 at 19:10
  • Finally, if none of these suggestions apply to your scenario and what you are needing is just a version number string for including in telemetry and you can't manifest the EXE you are running in, then you can fall back to using the technique described in [KB167597](https://support.microsoft.com/en-us/kb/167597) on a known system DLL like ``kernel32.dll``. Again, don't parse the version number string or do any code checks with it at all or you are just creating the same appcompat problems again. Just put it into your logs/report and let a human read it on the other end. – Chuck Walbourn Jul 31 '15 at 19:14
  • The ``GetVersionEx`` deprecation was reasonably well communicated on MSDN and through VS 2013/2015 warnings. The ``VerifyVersionInfo`` behavior change has not ben properly documented, but it is live on millions of Windows 10 RTM machines right now. – Chuck Walbourn Jul 31 '15 at 19:15
  • @ChuckWalbourn Thanks for all of the info. The application is mainly just a diagnostics program which shows some system information to the user. The version info is really only used to display it to the user, not to do any version checking in the code. Basically the string returned by my GetWinVersion function is what is shown to the user. What would be your suggestion for this? This is really what I want to know for the question I am asking. Thanks. – Evan Zimmerman Jul 31 '15 at 19:30
  • 3
    Use WMI to query the system version – David Heffernan Jul 31 '15 at 19:32
  • @DavidHeffernan I just did some more digging and to answer your question, Chuck appears to be right about VerifyVersionInfo being depreciated in Windows 10. I did not notice this when browsing the MSDN at first since it is stated at the bottom of the page: https://msdn.microsoft.com/en-us/library/windows/desktop/ms725492(v=vs.85).aspx – Evan Zimmerman Jul 31 '15 at 19:37
  • @Evan I'm not doubting him. Note also that it was Chuck that added that comment to the docs. I was wanting to learn more. I thought VerifyVersionInfo required supportedOS manifest even on 8.1. – David Heffernan Jul 31 '15 at 19:39
  • @DavidHeffernan Oh I didn't think you were, I just thought I would share the info I found. Do you happen to have an example on how to use WMI in Delphi to query the OS version? Or a link to an example? That would be entirely new to me. Thanks. – Evan Zimmerman Jul 31 '15 at 19:42
  • 3
    Is there an example at the dupe? There's always Rodrigo Ruz's wmi query builder. Search for that. – David Heffernan Jul 31 '15 at 19:43
  • 3
    https://theroadtodelphi.wordpress.com/wmi-delphi-code-creator/ – David Heffernan Jul 31 '15 at 19:47
  • After a quick test, the WMI query appears to be working for getting the version info. Thanks for providing the link. – Evan Zimmerman Jul 31 '15 at 20:12
  • WMI is indeed the appropriate way to go here. On a side note however, there have been a couple cases where I've found our clients' IT person disabled WMI for some strange reason. On my system it won't even let me stop it though. – Jerry Dodge Jul 31 '15 at 23:33
  • you have to add a applciation manifest wit hthe supportOS Guid to tell Windows that you fully support 8.1/10. Now GetVErsionEx reports the correct values o not 6.2 – magicandre1981 Aug 01 '15 at 05:15
  • 1
    @magic No, that's not the answer. Works right up until the next version is released. Please read the documentation where you are expressly told not to do that. – David Heffernan Aug 01 '15 at 13:34
  • Using WMI is definitely the way to go. Tested and works on both 8.1 and 10.0. You do not need a manifest. I will post my updated code on Monday when I have access to my PC again. – Evan Zimmerman Aug 01 '15 at 13:52
  • @DavidHeffernan Delphi doesn't have the Helper functions, so adding the manifest + GUID is fine. – magicandre1981 Aug 01 '15 at 17:18
  • 2
    @magic No it's not fine. I explained why not. The MSDN docs are clear. I call the version helpers from delphi. – David Heffernan Aug 01 '15 at 17:39
  • @ChuckWalbourn, I do version check as well i my apps., This is not to tie them to that version, but in fact to get them working on that version. Is that not what everyone does ? It is also part of the logs that I get from users, in case the issue is windows specific. – Rohit Gupta Aug 01 '15 at 23:52
  • @Rohit Define "version check" – David Heffernan Aug 02 '15 at 07:17
  • The new MS way to go is for application to crash and for developer to dive into telemetry dump, lol. – Free Consulting Aug 02 '15 at 13:52
  • @RohitGupta: So again, years of experience in doing new versions of Windows informs the appcompat team that many popular applications routinely use the results of this API in ways that break with minor changes to the version number. One of the long-standing tests in the Application Verifier has been a version lie that returns a higher than normal version number. Unfortunately, many people have responded to the deprecation of ``GetVersionEx`` by just reinventing the problem with ``VerifyVersionInfo`` and that's partly because of poor documentation on MSDN. Most version checks aren't needed. – Chuck Walbourn Aug 02 '15 at 17:41
  • @DavidHeffernan, the version number is just for logging. But OS "Name" such as XP/Vista is what I have to use for code differences. – Rohit Gupta Aug 02 '15 at 20:35
  • @RohitGupta That makes no sense to me at all. – David Heffernan Aug 02 '15 at 20:35
  • @ChuckWalbourn, if the windows was the same from version to version (pardon me while I roll on the floor) then we wouldn't need to worry about it. But while MS keeps playing games such as targetting Lotus with 95 and then firebird/interbase with XP and changing how the painting happens in XP/Vista then people will keep finding ways to detect it. – Rohit Gupta Aug 02 '15 at 20:39
  • 12-13 years ago the PC world was quite different. As of Windows 10 the version number doesn't actually mean all that much because of the new Windows as a Service model. In any case, if the default behavior of ``GetVersionEx`` or ``VerifyVersionInfo`` isn't what you need, then add the ```` manifest to your EXE and use ``#pragma warning(suppress :4996)`` in your source files. That's already been stated as the robust solution. I realize there are reasons this solution doesn't work for everyone, but it should work for most people if they can't just eliminate the version check. – Chuck Walbourn Aug 02 '15 at 21:23
  • To be clear, for down-level OS support you still do have to deal with feature detection, explicit linking with fallback, and all the other usual challenges but those can be done robustly without using version checks. It is the use of version checks to arbitrarily "lock" the app to an OS release or to do feature detection that has been the problem. – Chuck Walbourn Aug 02 '15 at 21:25

0 Answers0