In Windows, if you want the windows.h
header file to default to the Unicode character set, you need to define the UNICODE
symbol:
#define UNICODE #include <windows.h>
There’s no point defining the symbol after the horse has left the barn:
// Code in italics is wrong #include <windows.h> #define UNICODE
Related: Don’t forget to #define UNICODE if you want Unicode.
Now, sure, a mistake like that is pretty obvious and easy to spot.
But other mistakes might not be so easy to find.
#include <stdio.h> #include <contoso.h> #include <fastmalloc.h> #define UNICODE #include <windows.h> extern HWND g_mainWindow; void UpdateTitle(PCWSTR title) { SetWindowText(g_mainWindow, title); }
This looks perfectly fine: We defined the UNICODE
symbol before we included windows.h
, but we still get compiler errors that suggest that the symbol didn’t take effect:
error C2664: 'BOOL SetWindowTextA(HWND,const char *)': cannot convert argument 2 from 'const wchar_t *' to 'const char *' note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
The error message tells us that the compiler thinks that SetWindowText
redirects to SetWindowTextA
, and that function expects an ANSI string, not a Unicode one. But how can that be? We did the right thing and defined UNICODE
symbol immediately before including windows.h
.
Yes, you defined it immediately before you included windows.h
. But your inclusion of windows.h
isn’t the one that counted.
Somewhere in the chain of #include
files that came before you included windows.h
is somebody that did their own #include <windows.h>
. That first inclusion did not have the UNICODE
symbol defined, so the result was that all of the Windows macros redirected to the ANSI versions. You reconfigured the windows.h
header afterward, but by then it was too late.
You’ll need to move the definition to somewhere that occurs before the point at which the windows.h
header is included for the first time. The safest place is to do it before including anything.
#define UNICODE
#include <stdio.h>
#include <contoso.h>
#include <fastmalloc.h>
#include <windows.h>
Bonus chatter: If you want to find out who is doing the early inclusion of windows.h
, you can pass the /showIncludes
command line option to the Microsoft Visual C++ compiler. This can be configured in Visual Studio under Project → Configuration Properties → C/C++ → Advanced → Show Includes = Yes (/showIncludes). This will generate a hierarchy tree of every included file, and you can search it to see who included windows.h
.
For gcc, you don’t even need to do that much. You can reuse a trick we saw a little while ago: Give a macro a conflicting definition and wait for the fireworks.
#define CreateFile who_includes_windows_h_first
#define UNICODE
#include <stdio.h>
#include <contoso.h>
#include <fastmalloc.h>
#include <windows.h>
You will then get told
in file included from /sdk/fileapifromapp.h:19: from /sdk/winbase.h:42: from /sdk/windows.h:171: from /contoso/inc/internal/config.h:84: from /contoso/inc/contoso.h:20: /sdk/fileapi.h:84: warning: "CreateFile" redefined
Bingo, it’s contoso.h
, via its helper include file internal/config.h
.
I wonder if
contoso.h
even supports usingwindows.h
in Unicode mode. In my opinion the more robust solution is to always use theW
-suffixed function names and explicitwchar_t
-based type names (à la C++/WinRT). There should also be a supercharged version ofNOMINMAX
that disables all redirection macros.Believe it or not you can't get rid of all the redirection macros, unfortunately there is a bug (feature?) in quite a few APIs that have symbols identical to GDI names (ex: ID2D1RenderTarget::DrawText collides with GDI DrawText) Such that the actual name in the vtable is actually so if you try to compile this without redirection macros enabled you end up with symbol errors unfortunately... I've tried because it annoyed me. I'm fairly sure...