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

标签 windows visual-studio visual-studio-2012 windows-7 platform

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

enter image description here

我有两个问题。首先,出于病态的好奇,为什么 Microsoft 将 _WIN32_WINNT 设置为对执行环境无效的值?我能理解用户是否想要这样做,但微软不行,因为它会破坏一切 (q.v.)。

其次,我们如何将WINVER_WIN32_WINNT 设置为符号“This Platform”?在这种情况下,“此平台”是 Windows 7。当我在 Windows Vista 上测试时,它将是一个不同的平台。当我在 Windows 8 上测试时,它将是另一个平台。当我在 ARM 开发人员提示下针对 Windows Phone 和 Windows Store 进行测试时,它将是另一个平台。


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

  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 and 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

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


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

#ifdef CRYPTOPP_WIN32_AVAILABLE
# ifndef _WIN32_WINNT
#  define _WIN32_WINNT 0x0400
# endif
#endif

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

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


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

最佳答案

“此平台”隐含在平台工具集中。 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++ Team blog了解详情。

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

#include <WinSDKVer.h>
#define _WIN32_WINNT 0x0600 // Windows Vista SP2 or later
#include <SDKDDKVer.h>

#include <WinSDKVer.h>
#define _WIN32_WINNT 0x0601 // Windows 7 or later
#include <SDKDDKVer.h>

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

If you need support for Windows XP SP3 or Windows Server 2003 SP2, then you have to use an alternative Platform Toolset setting which selects the Windows 7.1A SDK. See this post for some notes about the differences.

参见 Using the Windows Headersthis blog article

Keep in mind that VS 2015 itself does not support targeting Windows 7 RTM, only Windows 7 Service Pack 1.

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

    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

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

关于windows - Visual Studio 在 Windows 7 上将 WINVER/_WIN32_WINNT 设置为 Windows 8?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37668692/

相关文章:

visual-studio - 使用多设备混合应用程序构建 Visual Studio Cordova 应用程序时出错

visual-studio - 如何链接到 MVC4 中的区域

c# - Visual Studio + 单声道 : 'Gtk' could not be found

windows oneliner 在环境变量中设置命令输出

c# - 我怎样才能避免 ZedGraph 重新标记我的 YAxis,除以 1000?

windows - 无法让 Freeglut 在 Windows 上与 Haskell 一起工作

c++ - 为函数定义符号不明确的指针参数

visual-studio-2012 - Visual Studio 2012 中的 Ctrl-Tab 行为

windows - 将计算机名称和用户名传递到批处理脚本中

windows - 如何在 Windows 上为 GeoDjango 安装 GEOS