3

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:

enter image description here

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 (q.v.).

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".

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • To the close-voter and down-voter: perhaps you missed this: ***"It appears Microsoft's toolchain is setting `_WIN32_WINNT` to `0x602` (`_WIN32_WINNT_WIN8`)"***. We are not setting `WINVER` or `_WIN32_WINNT` - Microsoft's toolchain is setting it, and its not clear to me how to provide you with anything other than the statement we are not doing it. I can only offer evidence that we react to Microsoft's bogus values. – jww Jun 07 '16 at 01:02
  • @Andrew - what MVCE? We are not doing it, so there's nothing to offer. – jww Jun 07 '16 at 01:10
  • That's nonsense. You're running commands and building code. Show them/it. – nobody Jun 07 '16 at 01:13
  • @Andrew - I get the impression you're not up-to-speed on this subject of `WINVER`, `_WIN32_WINNT` and using the Windows headers. Perhaps you should sit this one out. – jww Jun 07 '16 at 01:16
  • I'm quite well versed, thank you. You're the one who's having trouble. – nobody Jun 07 '16 at 01:19
  • @Andrew - you don't appear to be as well versed as you think. Otherwise, the problem we are experiencing would likely be old-hat for you and I'm guessing you would have jumped in with your answer. – jww Jun 07 '16 at 01:41
  • *The wrong WINVER and _WIN32_WINNT will be set regardless of what's in the file.* - could you clarify what you mean by "wrong"? If you haven't set a value yourself, the default should be determined by the version of the SDK you're using; that's by design, as Michael and Chuck's answers explain. (Incidentally, you do realize that you should be testing your application on a machine that doesn't have *any* version of Visual Studio installed? That's how most end users will be using it, after all.) – Harry Johnston Jun 07 '16 at 08:59
  • ... or are you talking about a library, and you're wanting to build it against a test suite application or similar, specifically to run on your machine? – Harry Johnston Jun 07 '16 at 09:26
  • If your goal is to support UWP without breaking desktop, does [this article](https://msdn.microsoft.com/en-us/library/mt186162.aspx) help? – Harry Johnston Jun 07 '16 at 20:58
  • See also http://stackoverflow.com/a/5440567/886887 – Harry Johnston Jun 08 '16 at 04:14

4 Answers4

7

"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.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • 1
    He does not have to reconfigure his project for each version of Windows, but he does have to have distinct builds for Win32 classic desktop with down-level support vs. UWP vs. Windows 8 Store vs. Windows 8.1 Store vs. Windows phone 8 vs. Windows phone 8.1. In general you can't build a single binary that will work in all these cases. BTW, at this point there's little reason to support Windows 8.0 Store or Windows phone 8.0 or VS 2012 generally. – Chuck Walbourn Jun 07 '16 at 15:50
4

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).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Thanks Michael. How do we set it to the symbolic "this platform". Its useless and idiotic to set it to Windows 8 for a Windows 7 build and execution environment. It breaks things. – jww Jun 07 '16 at 01:04
  • The Windows SDKs/Microsoft toolchains do not have a "this platform" concept. Each one has a default that it will target (either the named platform for "Windows SDK"s or typically whatever was current for VS toolchains). If you want to target a specific OS you either use an SDK that targets it by default or you have to specify it. `-march` is totally irrelevant - it's about CPU features, not OS version. – nobody Jun 07 '16 at 01:16
  • Thanks again Michael. This one is tough for us: *`/D _WIN32_WINNT=0x0601`* because it causes us to make a wrong choice somewhere. If we set `/D _WIN32_WINNT=0x0601` and a user wants to upgrade the project files to VS2015 for Windows Store 10, then its broken for them. I'm guessing this will be one of those black-hole questions that does not develop a solution, and [our bug report for the issue](http://github.com/weidai11/cryptopp/issues/178) will remain open for years. – jww Jun 07 '16 at 01:37
  • @Andrew - OK, so you seem to be one of those argumentative folks. What part of ***`GCC has a quasi-similar -march=native` ....*** was vague or don't you understand? I gave you an example of something similar that captures the essence of "this platform". – jww Jun 07 '16 at 01:47
  • It was perfectly clear; the point is the MS toolchains do not have an equivalent for "target platform version". – nobody Jun 07 '16 at 01:51
  • I don't know anything about projects that build for Windows Store 10. but if it's a different target platform, then it seems like you'd need a different project configuration for it. Specify the correct `_WIN32_WINNT` value for the project that builds for that target. – Michael Burr Jun 07 '16 at 05:45
  • In the past, I've had to edit Windows header files to clear the warnings they introduce at `/W4` and `/Wall` (also see the [Off By Default warnings](https://blogs.msdn.microsoft.com/vcblog/2010/12/14/off-by-default-compiler-warnings-in-visual-c/)). I'm thinking I'm probably going to fix these headers the same way. – jww Jun 07 '16 at 10:16
  • 2
    Maybe I'm misunderstanding something about what you want to do, but that seems to be an extreme way to fix something that can be fixed with a project/makefile setting. – Michael Burr Jun 07 '16 at 15:12
  • @MichaelBurr - *"that seems to be an extreme way to fix something that can be fixed with a project/makefile setting"* - Please forgive my ignorance... how do we fix it? If we set it ***`/D _WIN32_WINNT=0x0601`*** for Windows 7, then things are broke for down-level and up-level clients. Down-level clients, like XP, won't have some of the APIs. Up-level clients will miss features. Its especially important to keep up-level clients happy because Microsoft is missing crucial APIs at [Windows Phone 8 and Windows Store 8](http://stackoverflow.com/q/36974545). – jww Jun 08 '16 at 19:54
  • My answer already explains all of that - there are macro definitions you can use to detect Phone/Store/UWP builds, and for desktop builds you either aim at the lowest supported OS or choose the API at runtime. And if you don't want to do that, and really only ever run the output executable on the same machine that built it, you can use a pre-build step. Is there something that's still unclear? – Harry Johnston Jun 08 '16 at 21:25
2

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.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • Actually this is a complete legitimate use of the ``_WIN32_WINNT`` preprocessor define. Explicit linking has runtime overhead, and you can't use explicit linking with UWP anyhow. See [this blog post](https://blogs.msdn.microsoft.com/chuckw/2012/09/17/dual-use-coding-techniques-for-games-part-1/) – Chuck Walbourn Jun 07 '16 at 04:57
  • @ChuckWalbourn: aren't shared libraries kind of a special case? – Harry Johnston Jun 07 '16 at 07:02
  • There are features and APIs that are worth checking for and having a soft-fail fallback, but they have a runtime cost. This kind of low-level Win32 API is probably not it. – Chuck Walbourn Jun 07 '16 at 15:38
  • @ChuckWalbourn: that's a good point; in this particular case, at least, he isn't even using the additional functionality provided by the newer API. I've rewritten accordingly. – Harry Johnston Jun 07 '16 at 20:54
-1

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.

jww
  • 97,681
  • 90
  • 411
  • 885
  • 1
    "Community support" are not engineers and don't always know what they're talking about. If you follow the link in that answer, it explicitly says that Windows 7 *is* supported. (Of course, "supported" just means that it works as designed, not that it works the way you want it to.) – Harry Johnston Oct 09 '16 at 00:27