警告C4996:'GetVersionExW':声明已弃用

yem*_*ans 32 wdk visual-c++ visual-studio-2013

我正在Win 8.1中使用VS 2013.如何解决这个警告?

Chu*_*urn 53

基本问题是"你为什么GetVersionExW要先打电话?" 这个问题的答案决定了你应该做什么.

弃用警告可以让开发人员了解在Windows 8.1中启动的appcompat行为更改.请参阅Windows和Windows Server兼容性菜谱:Windows 8,Windows 8.1和Windows Server 2012.简而言之,该函数不会返回您认为默认返回的内容.

从历史上看,写得不好的操作系统版本检查是Windows操作系统升级的appcompat错误的主要来源.有许多不同的方法可以尝试缓解这个问题(AppVerifier版本谎言,VerifyVersionInfoAPI等),这是迄今为止最具侵略性的方法.

VersionHelpers.h在评论中提到的是Windows 8.1 SDK附带的Visual Studio 2013年他们是不是一个新的API; 它们只是利用VerifyVersionInfoWindows 2000中引入的API的实用程序代码.这些函数用于执行"你必须这么高才能骑这种方式"的样式检查,这些检查是最常写的版本检查.代码非常简单.例如,IsWindowsVistaSP2OrGreater测试是:

VERSIONHELPERAPI
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
    OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
    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);
}
Run Code Online (Sandbox Code Playgroud)

您不需要使用,VersionHelpers.h因为您可以自己执行此类代码,但如果您已经在使用VS 2013编译器,则它们很方便.对于游戏,我有一篇文章版本号是什么?它使用VerifyVersionInfo做的那种人不应因游戏部署合理检查.

请注意,如果您使用带有v120_xp平台工具集的VS 2013 来定位Windows XP,那么您实际上将使用Windows 7.1A SDK并且#include <VersionHelpers.h>无法使用.你当然可以VerifyVersionInfo直接使用.

另一个主要用途GetVersionExW是诊断日志和遥测.在这种情况下,一种选择是继续使用该API,并确保您的应用程序中有正确的清单条目,以确保合理准确的结果.有关您在此处执行此操作的详细信息,请参阅Manifest Madness.要记住的主要事情是,除非您定期更新代码,否则最终将无法在未来版本的操作系统中获得完全准确的信息.

请注意,建议您将该<compatibility>部分放入嵌入式清单中,无论您是否关心GetVersionEx作为一般最佳实践的结果.这允许操作系统根据最初测试应用程序的方式自动应用未来的appcompat修复程序.

对于诊断日志,另一种可能更健壮的方法是从系统DLL中获取版本号,如kernel32.dll使用GetFileVersionInfoW.这种方法有一个重要的问题:不要尝试解析,进行比较,或根据您通过这种方式获得的文件版本进行代码假设; 把它写出来.否则,您冒着重新创建同样糟糕的操作系统版本检查问题的风险VerifyVersionInfo.此选项不适用于Windows应用商店应用,Windows手机应用等,但应适用于Win32桌面应用.

#include <windows.h>
#include <stdint.h>
#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;
}
Run Code Online (Sandbox Code Playgroud)

如果你有其他原因要打电话GetVersionExW,你可能不应该打电话给它.检查可能缺少的组件不应与版本检查绑定.例如,如果你的应用需要媒体基金会,您应该设置一个"你必须是此高骑这搭检查"之类的VersionHelpers.h IsWindowsVistaOrGreater部署,但在运行时,你应该通过使用显式链接LoadLibraryLoadLibaryEx报告错误或使用如果MFPLAT.DLL找不到,则回退.

显式链接不是Windows应用商店应用的选项.Windows 8.x通过使用存根来解决此特定问题MFPLAT.DLL,MFStartUp并将返回E_NOTIMPL.请参阅"谁移动了我的[Windows Media]奶酪"?

另一个例子:如果您的应用程序想要使用Direct3D 11.2(如果可用)并使用DirectX 11.0,您IsWindowsVistaSP2OrGreater可以使用D3D11InstallHelper设置最小条进行部署.然后在运行时,您将创建DirectX 11.0设备,如果它失败,您将报告错误.如果您获得了a ID3D11Device,那么您将QueryInterface获得一个ID3D11Device2,如果它成功意味着您正在使用支持DirectX 11.2的操作系统.请参阅Direct3D 11创建设备的剖析.

如果这个假设的Direct3D应用程序支持Windows XP,您将使用IsWindowsXPSP2OrGreater或的部署栏IsWindowsXPSP3OrGreater,然后在运行时使用显式链接来尝试查找D3D11.DLL.如果它不存在,你将回归使用Direct3D 9 - 因为我们设置了最小条,我们知道DirectX 9.0c或更高版本始终存在.

他们的关键点在于,在大多数情况下,你不应该使用GetVersionEx.

请注意,对于Windows 10,VerifyVersionInfo并且通过GetFileVersionInfokernel32.lib 获取文件版本标记现在受到与基于清单的行为相同的行为GetVersionEx(即,没有Windows 10的清单GUID,它返回结果,就好像操作系统版本是6.2而不是10.0 ).

对于Windows 10上的通用Windows应用程序,您可以使用新的WinRT API AnalyticsInfo来获取诊断日志和遥测的版本标记字符串.

  • 我在这里被投了几次.如果只是因为你讨厌"GetVersionEx`"首先被弃用,你就是在射击信使:) (9认同)
  • 在单个句子上对一个1000字的帖子进行音调管理似乎很奇怪,但我已经编辑了这个语句.无论如何,开发人员和appcompat人员之间的"GetVersion"战斗已经持续了多年,但是这个答案的指导与我能做到的完全一样. (6认同)
  • "你不应该打电话",因为"你错了,你应该感觉不好",可以解释一下. (3认同)

use*_*233 10

您可以通过添加以下内容来禁用此警告并使用 GetVersionEx:

#pragma warning(disable : 4996)
Run Code Online (Sandbox Code Playgroud)

  • C4996 警告告诉您“GetVersionEx”不一定再做您认为它做的事情。您当然可以禁用 Windows 桌面应用程序的警告,但请注意,它会欺骗您。因此,我上面的回答中给出了指导。 (9认同)