How to target XP with VC2012 or VC2013 and continue to use the Windows 8.x SDK

One of the limitations of the Microsoft provided solution for targeting XP while using Visual Studio 2012 (Update 1 and above), or Visual Studio 2013, is that you must use a special “Platform toolset” in project properties that forces usage of the Windows SDK 7.1 (instead of Windows 8.x SDK which is the default).  The other function the platform toolset provides is that it sets the Linker’s “Minimum Required Version” setting to 5.01 (instead of 6 which is the default).  But that function can just as easily be done manually by setting it in project properties.

So how about the first main function of the platform toolset?   Setting the platform toolset to one that targets XP does the following:

(1) Changes the Platform SDK being used from Windows SDK 8.x (8.1 with VC2013 and 8.0 with VC2012) back to Windows SDK 7.1

(2) Adds a preprocessor define:  _USING_V110_SDK71_ to the build

The second one turns out to be important, due to a piece of code in atlwinverapi.h, namely the following:

extern inline BOOL __cdecl _AtlInitializeCriticalSectionEx(__out LPCRITICAL_SECTION lpCriticalSection, __in DWORD dwSpinCount, __in DWORD Flags)
#if (NTDDI_VERSION >= NTDDI_VISTA) && !defined(_USING_V110_SDK71_) && !defined(_ATL_XP_TARGETING)
     // InitializeCriticalSectionEx is available in Vista or later, desktop or store apps
     return ::InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags);
     // ...otherwise fall back to using InitializeCriticalSectionAndSpinCount.
     return ::InitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount);

As you can see, if we do not use the platform toolset that defines _USING_V110_SDK71, i.e we don’t use the Windows SDK 7.1, then we don’t get the benefit of avoiding a call to InitializeCriticalSectionEx, which is a function only available on Vista and above.  This will cause your binary to not load on XP.

But what if we really want to use the Windows 8.x SDK (taking care, of course, that we don’t call any Windows 8.x functions directly, to keep support for older operating systems). Why would we want this? For example, we may want a structure definition, some preprocessor define, or function declaration, i.e. we may want to support some feature of Windows 8.x if actually running our app on that OS.

Say we’ve decided to use Windows 8.x SDK while still allowing our app to run on XP. Are there any options available? i.e. can you keep using the v110/v120 toolsets instead of the v110_xp/v120_xp toolsets? Yes, it turns out that Microsoft left a nice loophole in the code to do exactly that. Notice the mysterious define in the block of code above named _ATL_XP_TARGETING. Turns out this is an alternative way to support XP targeting while _USING_V110_SDK71_ is NOT defined. So if you really want to support XP while using Windows 8.x SDK, we simply need to ensure our code is built with _ATL_XP_TARGETING defined. The easiest way to do this is to add a /D_ATL_XP_TARGETING flag to our C/C++ command line options in project properties.

Then, the only other step is to set the “Minimum Required Version” in project properties under Linker – System to 5.01, and we’re all set – a simple way to target XP and still use the Windows 8.1 SDK without using the platform toolset that Microsoft provided to target XP.

In summary, the _ATL_XP_TARGETING define, while undocumented, is an interesting way to keep support for XP while also allowing continued use of the Windows 8.x SDK (rather than being forced to be permanently stuck on  the older Windows 7.1 SDK)