我正在使用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
:
我有两个问题。首先,出于病态的好奇心,为什么Microsoft将_WIN32_WINNT
设置为对执行环境无效的值?我可以理解用户是否想要这样做,但不是微软,因为它破坏了事情( q.v。)。
其次,我们如何将WINVER
或_WIN32_WINNT
设置为符号"此平台"?在这种情况下,"这个平台"是Windows 7.当我在Windows Vista上进行测试时,它将是一个不同的平台。当我在Windows 8上测试时,它将是另一个平台。当我在ARM开发人员提示下测试Windows Phone和Windows Store时,它将是另一个平台。
问题很容易复制。这是步骤。我想任何拥有良好测试环境的人都已经有了前八个步骤。
然后:
我可以发布MCVE,这是一个空的源文件,以安抚一些人。这似乎是浪费时间,因为问题在于工具链而不是源文件。空hello_world.cpp
对这个问题真的至关重要吗?无论文件中包含哪些内容,都会设置错误的main
和WINVER
。
我知道错误的起源。我们的代码最近更改为更好地支持Windows 8, Phone 8, Store 8, Server 2012, Windows 10, Phone 10, Store 10 and Windows Universal Platform。变化看起来像这样:
_WIN32_WINNT
具有讽刺意味的是,我们添加了#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
的调用以首先安抚工具。他们抱怨已弃用的功能并导致脏编译。肮脏的编译为用户创造了治理,C&amp; A和ST&amp; E问题。
我审核了代码,以确保我们不会无意或错误地设置值。我验证了我们在一个地方执行此操作,并且代码路径未激活,因为Microsoft的工具链正在将值设置为GetOverlappedResultEx
:
0x602
这是一个相关的堆栈溢出问题:What is WINVER?,但它没有讨论如何将其设置为&#34;此平台&#34;。
以下是Microsoft关于该主题的文档:Using the Windows Headers和Modifying WINVER and _WIN32_WINNT。具有讽刺意味的是,他们并没有真正讨论这个问题或Windows 10,Windows Phone 10,Windows Store 10或Windows Universal Platform。
顺便说一下,海湾合作委员会有一个准相似的#ifdef CRYPTOPP_WIN32_AVAILABLE
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
# endif
#endif
基本上提供了这个平台&#34;。
答案 0 :(得分:4)
如果您没有明确提供目标平台版本,那么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)。
答案 1 :(得分:3)
“此平台”隐含在平台工具集中。 VS 2012使用默认为_WIN32_WINNT=0x0602
的Windows 8.0 SDK(Windows 8)。 VS 2013/2015使用默认为_WIN32_WINNT=0x0603
的Windows 8.1 SDK(Windows 8.1)。如果您使用VS 2015和Windows 10 SDK,则默认为_WIN32_WINNT=0x0A00
(Windows 10)。
这主要是为了Windows Store / UWP应用程序的优势,这些应用程序需要_WIN32_WINNT
的最新值才能正确构建。在Windows 10中,_WIN32_WINNT
值未按构建版本进行更新,因此您可以配置要使用的并行Windows 10 SDK。有关详细信息,请参阅Visual C++ Team blog。
对于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的平台工具集设置。有关差异的一些注释,请参阅this post。
请参阅Using the Windows Headers和this blog article
请记住,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。
答案 2 :(得分:2)
这里的根本问题是您使用_WIN32_WINNT
来确定要采用的代码路径,但不是实际设置它。这适用于Windows Store / Phone / UWP版本(如Chuck的回答所述),但不适用于桌面版本。
对于桌面版本,正确的解决方案是使用最小公分母或在运行时选择代码路径。否则,您需要为不同版本的Windows构建不同的桌面可执行文件。
在这种特殊情况下,由于您没有使用GetOverlappedResultEx
提供的附加功能,因此坚持使用GetOverlappedResult
进行桌面构建可能更为明智。您可以使用How to: Use Existing C++ Code in a Universal Windows Platform App中列出的宏定义来确定是否为桌面构建。
桌面应用似乎不推荐使用GetOverlappedResult
API,因此如果您使用GetOverlappedResultEx
进行UWP / Store / Phone构建,则不应进行脏编译。 (?)
据我所知,没有非常优雅的方法可以使构建输出取决于运行构建工具的Windows版本 - 您将注意到the compiler的任何预定义宏都没有或者build environment允许您确定操作系统版本。
但是,如果这确实是适当的极少数情况之一,您可以通过使用预构建事件或自定义构建步骤来运行检查操作系统的程序版本并构造一个代码可以包含的头文件。如果其他Windows开发人员将构建您的库,我不会推荐它,因为他们不会期望这种行为;但是如果你需要它可以使用。
答案 3 :(得分:-1)
问题是(1)Microsoft营销文献声明Windows 7上的VS2012是受支持的配置;但是(2)Microsoft工程师在MSDN Community Support上声明它不是受支持的配置。所需的最低平台是Windows 8。