简体   繁体   中英

Visual Studio setting WINVER/_WIN32_WINNT to Windows 8 on Windows 7?

I'm performing some testing on Windows 7 x64 using Visual Studio 2012. It appears Microsoft's toolchain is setting _WIN32_WINNT to 0x602 ( _WIN32_WINNT_WIN8 ). Running our test program results in The procedure entry point GetOverlappedResultEx could not be located in the dynamic link library KERNEL32.dll :

在此处输入图片说明

I have two questions. First, out of morbid curiosity, why is Microsoft setting _WIN32_WINNT to a value that's not valid for the execution environment? I can understand if a user wants to do it, but not Microsoft since it breaks things ( qv ).

Second, how do we set WINVER or _WIN32_WINNT to the symbolic "This Platform"? In this case, "this platform" is Windows 7. When I test on Windows Vista, it will be a different platform. When I test on Windows 8, it will be another platform. And when I test under ARM developer prompt for Windows Phone and Windows Store, it will be yet another platform.


The problem is very easy to duplicate. Here are the steps. I imagine anyone with a good testing environment already has the first eight steps.

  1. Stand up a Windows 7, x64 machine
  2. Fully patch the Windows 7 machine
  3. Install Visual Studio 2008
  4. Fully patch Visual Studio 2008
  5. Install Visual Studio 2010
  6. Fully patch Visual Studio 2010
  7. Install Visual Studio 2012
  8. Fully patch Visual Studio 2012

Then:

  1. Create an empty "Hello World" project under VS2008
  2. Delete everything except hello_world.cpp (this should leave 1 solution file, and 1 project file, 1 source file)
  3. Convert it to VS2010
  4. Open with VS2012

I can post the MCVE, which is an empty source file, to appease some folks. It seems like a waste of time since the problem is with the toolchain and not the source file. Is an empty main really crucial to this problem? The wrong WINVER and _WIN32_WINNT will be set regardless of what's in the file.


I know the origin of the error. Our code changed recently to better support for Windows 8, Phone 8, Store 8, Server 2012, Windows 10, Phone 10, Store 10 and Windows Universal Platform . The changes look like so:

#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

Ironically, we added USE_WINDOWS8_API , the additional includes and the calls to GetOverlappedResultEx to appease the tools in the first place. They were complaining about deprecated functions and causing dirty compiles. The dirty compiles were creating governance, C&A and ST&E problems for users.


I audited the code to ensure we are not unintentionally or incorrectly setting the values. I verified we do it in one place, and the code path is not activated because Microsoft's toolchain is setting the value to 0x602 :

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

Here's a related Stack overflow question: What is WINVER? , but it does not discuss how to set it to "this platform".

Here's Microsoft's docs on the subject: Using the Windows Headers and Modifying WINVER and _WIN32_WINNT . Ironically, they don't really discuss the problem or Windows 10, Windows Phone 10, Windows Store 10 or Windows Universal Platform.


As an aside, GCC has a quasi-similar -march=native that basically provides "this platform".

"This platform" is implicit in the Platform Toolset. VS 2012 uses the Windows 8.0 SDK which defaults to _WIN32_WINNT=0x0602 (Windows 8). VS 2013 / 2015 uses the Windows 8.1 SDK which defaults to _WIN32_WINNT=0x0603 (Windows 8.1). If you use VS 2015 and the Windows 10 SDK, it defaults to _WIN32_WINNT=0x0A00 (Windows 10).

This is primarily done for the benefit of Windows Store / UWP apps which need the latest value for _WIN32_WINNT to build correctly. With Windows 10, the _WIN32_WINNT value isn't being updated build-to-build, so you configure which side-by-side Windows 10 SDK to use. See the Visual C++ Team blog for details.

For a Windows desktop app (aka classic Win32), you should explicitly set which version of the OS you support as part of your build configuration. Typically this is done in a pch.h or other global header, but can also be done via the build command-line/makefile/vcxproj:

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

or

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

The Windows 8.x SDK can target Windows Vista SP2, Windows 7, Windows 8.0, Windows 8.1 or later.

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.

See Using the Windows Headers and this blog article

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

For the specific case of GetOverlappedResultEx , I use the following pattern in my code that supports building for both down-level Windows 7 as well as 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

I then provide multiple builds of my static libraries for each supported platform. Remember that the WACK tool examines your EXE/DLL import & export tables, and will flag any unsupported API. As such, you can't have a runtime selection and must reference only the supported APIs in the "Windows 8" builds.

If you don't explicitly provide a target platform version, then the Windows SDK will select a default one (see the SDK's sdkddkver.h file for details).

For example, the Windows 8.0 SDK sdkddkver.h file has the following snippet:

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

If you don't want that default selection, you'll need to configure the target platform version by defining _WIN32_WINNT and/or the related macros appropriately. You can do that using the /D compiler option in the project settings or makefile, or you can define it in source files or a common header that is included by everything before including the SDK headers.

Something like /D _WIN32_WINNT=0x0601 might be appropriate for you (0x0601 corresponds to Win7).

The underlying problem here is that you're using _WIN32_WINNT to determine which code path to take, but not actually setting it. That's appropriate for Windows Store/Phone/UWP builds (as outlined in Chuck's answer) but not for desktop builds.

For desktop builds, the correct solution is to either use the lowest common denominator or to choose the code path at runtime. Otherwise you would need to build different desktop executables for different versions of Windows.

In this particular case, since you are not using the additional functionality that is provided by GetOverlappedResultEx , it would probably be more sensible to stick with GetOverlappedResult for desktop builds. You can use the macro definitions listed in How to: Use Existing C++ Code in a Universal Windows Platform App to determine whether you are building for desktop or not.

The GetOverlappedResult API does not appear to be deprecated for desktop apps, so provided you use GetOverlappedResultEx for UWP/Store/Phone builds, you shouldn't get dirty compiles. (?)


To the best of my knowledge there is no really elegant way to make the build output depend on the version of Windows that the build tools are running on - you will note that none of the predefined macros for either the compiler or the build environment allow you to determine the operating system version.

However, if this really is one of those rare cases where it is appropriate, you could do this by using a pre-build event or custom build step to run a program that checks the operating system version and constructs a header file which your code could include. If other Windows developers will be building your library, I wouldn't recommend it, because they will not be expecting this behaviour; but it is available if you need it.

The problem is (1) Microsoft marketing literature states VS2012 on Windows 7 is a supported configuration; but (2) Microsoft engineers state its not a supported configuration on MSDN Community Support . The minimum platform required is Windows 8.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM