Visual Studio 在 Windows 7 上将 WINVER/_WIN32_WINNT 设置为 Windows 8?

jww*_*jww 1 windows platform visual-studio windows-7 visual-studio-2012

我正在使用 Visual Studio 2012 在 Windows 7 x64 上执行一些测试。看来 Microsoft 的工具链设置_WIN32_WINNT0x602( _WIN32_WINNT_WIN8)。运行我们的测试程序结果The procedure entry point GetOverlappedResultEx could not be located in the dynamic link library KERNEL32.dll

在此处输入图片说明

我有两个问题。首先,出于病态的好奇心,为什么 Microsoft 设置_WIN32_WINNT的值对执行环境无效?我可以理解用户是否想要这样做,但不能理解 Microsoft,因为它破坏了事物(qv)。

第二,我们如何设置WINVER_WIN32_WINNT到象征性的“本平台”?在这种情况下,“这个平台”是 Windows 7。当我在 Windows Vista 上测试时,它将是一个不同的平台。当我在 Windows 8 上测试时,它将是另一个平台。当我在 Windows Phone 和 Windows Store 的 ARM 开发人员提示下进行测试时,它将是另一个平台。


这个问题很容易复制。以下是步骤。我想任何拥有良好测试环境的人都已经完成了前八个步骤。

  1. 架起一台 Windows 7, x64 机器
  2. 全面打补丁Windows 7机器
  3. 安装 Visual Studio 2008
  4. 完全修补 Visual Studio 2008
  5. 安装 Visual Studio 2010
  6. 完全修补 Visual Studio 2010
  7. 安装 Visual Studio 2012
  8. 完全修补 Visual Studio 2012

然后:

  1. 在VS2008下创建一个空的“Hello World”项目
  2. 删除所有内容,除了hello_world.cpp(这应该留下 1 个解决方案文件、1 个项目文件、1 个源文件)
  3. 将其转换为 VS2010
  4. 用 VS2012 打开

我可以发布 MCVE,这是一个空的源文件,以安抚一些人。这似乎是在浪费时间,因为问题在于工具链而不是源文件。空main对这个问题真的很重要吗?无论文件中的内容如何,​​都将设置错误WINVER_WIN32_WINNT


我知道错误的根源。我们最近更改了代码,以更好地支持Windows 8、Phone 8、Store 8、Server 2012、Windows 10、Phone 10、Store 10 和 Windows Universal Platform。更改如下所示:

#if defined(CRYPTOPP_WIN32_AVAILABLE)
# if ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/))
#  include <synchapi.h>
#  include <ioapiset.h>
#  define USE_WINDOWS8_API
# endif
#endif
...

#if defined(USE_WINDOWS8_API)
    BOOL result = GetOverlappedResultEx(GetHandle(), &m_overlapped, &m_lastResult, INFINITE, FALSE);
#else
    BOOL result = GetOverlappedResult(GetHandle(), &m_overlapped, &m_lastResult, FALSE);
#endif
Run Code Online (Sandbox Code Playgroud)

具有讽刺意味的是,我们首先添加USE_WINDOWS8_API了额外的包含和调用GetOverlappedResultEx来安抚工具。他们抱怨不推荐使用的函数并导致脏编译。脏编译给用户带来了治理、C&A 和 ST&E 问题。


我审核了代码以确保我们不会无意或错误地设置值。我验证了我们在一个地方执行此操作,并且代码路径未激活,因为 Microsoft 的工具链将值设置为0x602

#ifdef CRYPTOPP_WIN32_AVAILABLE
# ifndef _WIN32_WINNT
#  define _WIN32_WINNT 0x0400
# endif
#endif
Run Code Online (Sandbox Code Playgroud)

这是一个相关的堆栈溢出问题:什么是 WINVER?,但没有讨论如何将其设置为“此平台”。

这是微软关于这个主题的文档:Using the Windows Headers and Modifying WINVER and _WIN32_WINNT。具有讽刺意味的是,他们并没有真正讨论问题或 Windows 10、Windows Phone 10、Windows Store 10 或 Windows 通用平台。


顺便说一句,GCC 有一个 quasi-similar -march=native,基本上提供了“这个平台”。

Chu*_*urn 7

“此平台”隐含在平台工具集中。VS 2012 使用默认为_WIN32_WINNT=0x0602(Windows 8)的 Windows 8.0 SDK 。VS 2013 / 2015 使用默认为_WIN32_WINNT=0x0603(Windows 8.1)的 Windows 8.1 SDK 。如果您使用 VS 2015 和 Windows 10 SDK,则默认为_WIN32_WINNT=0x0A00(Windows 10)。

这样做主要是为了 Windows 应用商店/UWP 应用程序的利益,这些应用程序需要最新的值_WIN32_WINNT才能正确构建。对于 Windows 10,该_WIN32_WINNT值不会逐次更新,因此您可以配置要使用的并行 Windows 10 SDK。有关详细信息,请参阅Visual C++ 团队博客

对于 Windows 桌面应用程序(又名经典 Win32),您应该在构建配置中明确设置您支持的操作系统版本。通常这是在一个pch.h或其他全局头文件中完成的,但也可以通过构建命令行/makefile/vcxproj 完成:

#include <WinSDKVer.h>
#define _WIN32_WINNT 0x0600 // Windows Vista SP2 or later
#include <SDKDDKVer.h>
Run Code Online (Sandbox Code Playgroud)

或者

#include <WinSDKVer.h>
#define _WIN32_WINNT 0x0601 // Windows 7 or later
#include <SDKDDKVer.h>
Run Code Online (Sandbox Code Playgroud)

Windows 8.x SDK 可以针对 Windows Vista SP2、Windows 7、Windows 8.0、Windows 8.1 或更高版本。

如果您需要对 Windows XP SP3 或 Windows Server 2003 SP2 的支持,那么您必须使用选择 Windows 7.1A SDK 的替代平台工具集设置。有关差异的一些说明,请参阅此帖子

请参阅使用 Windows 标头此博客文章

请记住,VS 2015 本身不支持针对 Windows 7 RTM,仅支持 Windows 7 Service Pack 1。

对于 的特定情况GetOverlappedResultEx,我在我的代码中使用了以下模式,该模式支持为下层 Windows 7 以及 UWP/Windows 应用商店构建。

    HANDLE hEvent = CreateEventEx( nullptr, nullptr,
        CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE );

...

    // Read and verify header
    OVERLAPPED request = {};
    request.hEvent = hEvent;

    bool wait = false;
    if( !ReadFile( hFile, ..., &request ) )
    {
        DWORD error = GetLastError();
        if ( error != ERROR_IO_PENDING )
            return HRESULT_FROM_WIN32( error );
        wait = true;
    }

    DWORD bytes;
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
    BOOL result = GetOverlappedResultEx( hFile, &request, &bytes, INFINITE, FALSE );
#else
    if ( wait  )
        (void)WaitForSingleObject( hEvent, INFINITE );

    BOOL result = GetOverlappedResult( hFile, &request, &bytes, FALSE );
#endif
Run Code Online (Sandbox Code Playgroud)

然后,我为每个受支持的平台提供多个静态库版本。请记住,WACK 工具会检查您的 EXE/DLL 导入和导出表,并将标记任何不受支持的 API。因此,您无法选择运行时,并且必须仅引用“Windows 8”版本中受支持的 API。