Thursday, April 10, 2008

WINVER

We recently had a problem after migrating from Visual C++ 6.0 to 2005 where the message

WINVER not defined. Defaulting to 0x0502 (Windows Server 2003)

would appear while building MFC projects. After investigating this, here are my findings.

Prior to Visual C++ 2003, WINVER was defined in winres.h as the following:

  #ifndef WINVER
  #define WINVER 0x0400   // default to Windows Version 4.0
  #endif

In this case, WINVER was automatically defined to support Windows 95/98. With Windows 2000, a new platform sdk came out and in order to use it, it had to be installed and WINVER had to be manually changed to 0x0500 in stdafx.h.

Starting with 2003 (.NET), the definition of WINVER moved to afxv_w32.h and looked like this:

  #ifndef WINVER
  #  ifdef _WIN32_WINNT
  #    define WINVER _WIN32_WINNT
  #  else
  #    pragma message("WINVER not defined. Defaulting to 0x0501 (Windows XP and Windows .NET Server)")
  #    define WINVER 0x0501
  #  endif
  #else
  #  if WINVER < 0x0400
  #    error MFC requires WINVER to be #defined to 0x0400 or greater
  #  endif
  #endif

From that point on, WINVER stopped being silently defined. On Visual C++ 2005, afxv_w32.h looks like:

  #ifndef WINVER
  #  ifdef _WIN32_WINNT
  #    define WINVER _WIN32_WINNT
  #  else
  #    pragma message("WINVER not defined. Defaulting to 0x0502 (Windows Server 2003)")
  #    define WINVER 0x0502
  #  endif
  #else
  #  if WINVER < 0x0400
  #    error MFC requires WINVER to be #defined to 0x0400 or greater
  #  endif
  #endif

Now, the wizards were updated so that stdafx.h is correctly generated for new projects. The default file contains this part:

  // Allow use of features specific to Windows XP or later.
  #ifndef WINVER  
     // Change this to the appropriate value to target other
     // versions of Windows.
  #  define WINVER 0x0501 
  #endif

The problem is, the conversion tool that comes with 2005 modifies the project files, but (for obvious reasons) not the code. Which means we now get the message about WINVER being undefined.

Two solutions are possible:

  1. Add a define for WINVER in the project settings, in the proprecessor section. This works, but I don't usually like putting things in the project settings. It makes it harder to port the source code, since part of it depends on compiler/ide-specific stuff.

  2. Add a define in stdafx.h before anything is included (to reproduce what the default stdafx.h now looks like).

As for its value, it depends on what you want to support. If you want your application to run on Windows XP and later (including original version and SP1), WINVER should be 0x501. To use features from SP2, it should be 0x502.

As for the other related macros (_WIN32_WINNT, _WIN32_WINDOWS and _WIN32_IE), they should be set automatically, so no problem here. The generated stdafx.h does set these macros to specific values, but MFC headers will reproduce these values anyways. Define them if you need specific (and earlier) versions.

On Windows Vista, a new macro named NTDDI_VERSION is available. It should make this versioning thing a little bit easier.

Here are a few references: