Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

warning C4996: 'GetVersionExW': was declared deprecated

I am working on VS 2013 in Win 8.1. How to solve this warning?

like image 992
yemans Avatar asked Mar 10 '14 15:03

yemans


2 Answers

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.

like image 195
Chuck Walbourn Avatar answered Sep 21 '22 14:09

Chuck Walbourn


you can disable this warning and use GetVersionEx anyway by adding:

#pragma warning(disable : 4996) 
like image 22
user1438233 Avatar answered Sep 20 '22 14:09

user1438233