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

我正在使用Visual Studio 2012在Windows 7 x64上执行一些testing。它显示Microsoft的工具链将_WIN32_WINNT设置为0x602_WIN32_WINNT_WIN8 )。 运行我们的testing程序导致The procedure entry point GetOverlappedResultEx could not be located in the dynamic link library KERNEL32.dll

在这里输入图像说明

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

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


这个问题很容易复制。 这是步骤。 我想象有一个良好的testing环境的人已经有了前八步。

  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下创build一个空的“Hello World”项目
  2. 删除除hello_world.cpp以外的所有内容 (这应该留下1个解决scheme文件,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通用平台 。 更改如下所示:

 #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来安抚工具。 他们抱怨弃用的function,并导致脏编译。 肮脏的编译正在为用户创build治理,C&A和ST&E问题。


我审核了代码,以确保我们不是无意或不正确地设置值。 我证实我们在一个地方做,并且代码path不激活,因为微软的工具链设置值为0x602

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

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

这里是关于这个主题的微软文档: 使用Windows头和修改WINVER和_WIN32_WINNT 。 具有讽刺意味的是,他们并没有真正讨论这个问题,或者Windows 10,Windows Phone 10,Windows Store 10或Windows通用平台。


另外,海湾合作委员会有一个准类似的“ -march=native ,基本上提供了“这个平台”。

如果您没有明确提供目标平台版本,则Windows SDK将选择一个默认版本(请参阅SDK的sdkddkver.h文件以获取详细信息)。

例如,Windows 8.0 SDK sdkddkver.h文件具有以下代码片段:

 #if !defined(_WIN32_WINNT) && !defined(_CHICAGO_) #define _WIN32_WINNT 0x0602 #endif 

如果您不想要该默认选择,则需要通过适当地定义_WIN32_WINNT和/或相关的宏来配置目标平台版本。 您可以使用项目设置或makefile中的/D编译器选项来完成此操作,也可以在包含SDK标头之前在源文件或包含在所有内容中的通用标头中定义它。

/D _WIN32_WINNT=0x0601可能适合你(0x0601对应于Win7)。

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

这主要是为了Windows Store / UWP应用程序的好处,它需要_WIN32_WINNT的最新值才能正确构建。 在Windows 10中, _WIN32_WINNT值没有被更新到构建版本,因此您可以配置使用哪个并排的Windows 10 SDK。 有关详细信息,请参阅Visual C ++团队博客 。

对于Windows桌面应用程序(又名经典的Win32),您应该明确地设置您所支持的操作系统版本作为您的生成配置的一部分。 通常这是在pch.h或其他全局头文件中完成的,但也可以通过build命令行/ 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或更高版本。

如果您需要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 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。

这里的根本问题是,您正在使用_WIN32_WINNT来确定要采取的代码路径,但不是实际设置它。 这适用于Windows Store / Phone / UWP版本(如Chuck的答案中所述),但不适用于桌面版本。

对于桌面版本,正确的解决方案是使用最小公分母或在运行时选择代码路径。 否则,您将需要为不同版本的Windows构建不同的桌面可执行文件。

在这种特殊情况下,由于您没有使用GetOverlappedResultEx提供的附加功能,因此在桌面构建中使用GetOverlappedResult可能更为明智。 您可以使用“ 如何:在通用Windows平台应用程序中使用现有C ++代码”中列出的宏定义来确定您是否正在为桌面构建。

GetOverlappedResult API似乎不适用于桌面应用程序,因此,如果您为UWP / Store / Phone构建使用GetOverlappedResultEx ,则不应该弄脏编译。 (?)


据我所知,没有真正优雅的方法可以使构建输出依赖于构建工具运行的Windows版本 – 您将注意到编译器或构建环境的预定义宏都不允许您确定操作系统版本。

但是,如果这确实是适合的罕见情况之一,那么可以通过使用预生成事件或自定义生成步骤来运行程序来检查操作系统版本,并构建一个头文件包括。 如果其他Windows开发人员将建立你的图书馆,我不会推荐它,因为他们不会期待这种行为; 但如果你需要的话,它是可用的。

问题是(1)微软市场营销文献显示,Windows 7上的VS2012是受支持的配置; 但是(2)Microsoft工程师声明其在MSDN社区支持上不支持配置。 所需的最低平台是Windows 8。