The basic question is "why are you calling GetVersionExW
in the first place?" The answer to that question determines what you should do instead.
The deprecation warning is there to give developers a heads-up about the appcompat behavior change that started in Windows 8.1. See Windows and Windows Server compatibility cookbook: Windows 8, Windows 8.1, and Windows Server 2012. In short, that function doesn't return what you think it returns by default.
Historically, badly written OS version checks are the primary source of appcompat bugs for Windows OS upgrades. There've been a number of different approaches to trying to mitigate this problem (the AppVerifier version lie, the VerifyVersionInfo
API, etc.), and this is the most aggressive to date.
The VersionHelpers.h
mentioned in the comments are in the Windows 8.1 SDK that comes with Visual Studio 2013. They are not a new API; they are just utility code that makes use of the VerifyVersionInfo
API introduced back in Windows 2000. These functions are for doing "You must be this high to ride this ride" style checks which are the class of version checks that are most often badly written. The code is pretty simple. For example, the IsWindowsVistaSP2OrGreater
test is:
VERSIONHELPERAPI
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi = {};
osvi.dwOSVersionInfoSize = sizeof(osvi);
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
VERSIONHELPERAPI
IsWindowsVistaSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
}
You don't need to use VersionHelpers.h
as you could just do this kind of code yourself, but they are convenient if you are already using the VS 2013 compiler. For games, I have an article What's in a version number? which uses VerifyVersionInfo
to do the kind of reasonable checks one should for game deployment.
Note if you are using VS 2013 with the v120_xp
platform toolset to target Windows XP, you'll actually be using the Windows 7.1A SDK and #include <VersionHelpers.h>
won't work. You can of course use VerifyVersionInfo
directly.
The other major use of GetVersionExW
is diagnostic logs and telemetry. In this case, one option is to continue to use that API and make sure you have the right manifest entries in your application to ensure reasonably accurate results. See Manifest Madness for details on what you do here to achieve this. The main thing to keep in mind is that unless you routinely update your code, you will eventually stop getting fully accurate information in a future version of the OS.
Note that it is recommended you put the <compatibility>
section in an embedded manifest whether or not you care about the results of GetVersionEx
as general best practice. This allows the OS to automatically apply future appcompat fixes based on knowing how the app was originally tested.
For diagnostic logs, another approach that might be a bit more robust is to grab the version number out of a system DLL like kernel32.dll
using GetFileVersionInfoW
. This approach has a major caveat: Do not try parsing, doing comparisons, or making code assumptions based on the file version you obtain this way; just write it out somewhere. Otherwise you risk recreating the same bad OS version check problem that is better solved with VerifyVersionInfo
. This option is not available to Windows Store apps, Windows phone apps, etc. but should work for Win32 desktop apps.
#include <Windows.h>
#include <cstdint>
#include <memory>
#pragma comment(lib, "version.lib" )
bool GetOSVersionString( WCHAR* version, size_t maxlen )
{
WCHAR path[ _MAX_PATH ] = {};
if ( !GetSystemDirectoryW( path, _MAX_PATH ) )
return false;
wcscat_s( path, L"\kernel32.dll" );
//
// Based on example code from this article
// http://support.microsoft.com/kb/167597
//
DWORD handle;
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
DWORD len = GetFileVersionInfoSizeExW( FILE_VER_GET_NEUTRAL, path, &handle );
#else
DWORD len = GetFileVersionInfoSizeW( path, &handle );
#endif
if ( !len )
return false;
std::unique_ptr<uint8_t> buff( new (std::nothrow) uint8_t[ len ] );
if ( !buff )
return false;
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
if ( !GetFileVersionInfoExW( FILE_VER_GET_NEUTRAL, path, 0, len, buff.get() ) )
#else
if ( !GetFileVersionInfoW( path, 0, len, buff.get() ) )
#endif
return false;
VS_FIXEDFILEINFO *vInfo = nullptr;
UINT infoSize;
if ( !VerQueryValueW( buff.get(), L"\", reinterpret_cast<LPVOID*>( &vInfo ), &infoSize ) )
return false;
if ( !infoSize )
return false;
swprintf_s( version, maxlen, L"%u.%u.%u.%u",
HIWORD( vInfo->dwFileVersionMS ),
LOWORD(vInfo->dwFileVersionMS),
HIWORD(vInfo->dwFileVersionLS),
LOWORD(vInfo->dwFileVersionLS) );
return true;
}
If there is some other reason you are calling GetVersionExW
, you probably shouldn't be calling it. Checking for a component that might be missing shouldn't be tied to a version check. For example, if your application requires Media Foundation, you should set a "You must be this high to ride this ride check" like the VersionHelpers.h IsWindowsVistaOrGreater
for deployment, but at runtime you should use explicit linking via LoadLibrary
or LoadLibaryEx
to report an error or use a fallback if MFPLAT.DLL
is not found.
Explicit linking is not an option for Windows Store apps. Windows 8.x solves this
particular problem by having a stub MFPLAT.DLL
and MFStartUp
will return E_NOTIMPL.
See "Who moved my [Windows Media] Cheese"?
Another example: if your application wants to use Direct3D 11.2 if it is available and otherwise uses DirectX 11.0, you'd use set a IsWindowsVistaSP2OrGreater
minimum bar for deployment perhaps using the D3D11InstallHelper. Then at runtime, you'd create the DirectX 11.0 device and if it fails, you'd report an error. If you obtain a ID3D11Device
, then you'd QueryInterface
for a ID3D11Device2
which if it succeeds means you are using an OS that supports DirectX 11.2. See Anatomy of Direct3D 11 Create Device.
If this hypothetical Direct3D application supports Windows XP, you'd use a deployment bar of IsWindowsXPSP2OrGreater
or IsWindowsXPSP3OrGreater
, and then at run time use explicit linking to try to find the D3D11.DLL
. If it wasn't present, you'd fall back to using Direct3D 9--since we set the minimum bar, we know that DirectX 9.0c or later is always present.
They key point here is that in most cases, you should not use GetVersionEx
.
Note that with Windows 10, VerifyVersionInfo
and getting the file version stamp via GetFileVersionInfo
for kernel32.lib are now subject to the same manifest based behavior as GetVersionEx
(i.e. without the manifest GUID for Windows 10, it returns results as if the OS version were 6.2 rather than 10.0).
For universal Windows apps on Windows 10, you can a new WinRT API AnalyticsInfo to get a version stamp string for diagnostic logs and telemetry.