You're using the wrong character type

Hi. If I linked you to this thread, it's because I saw you making a very common mistake with WinAPI and I wanted to correct you.

You are passing the wrong type of string to WinAPI functions. That is, you're doing something like one of these:

1
2
MessageBox(NULL,      "This is wrong",       NULL,MB_OK);
MessageBox(NULL,     L"This is also wrong",  NULL,MB_OK);


Yes, yes... I know... the code is compiling just fine and is working for you. But really, it's wrong. Trust me. The correct way is to do one of these:

1
2
3
MessageBoxW(NULL,      L"This is right!"   ,NULL,MB_OK);
MessageBoxA(NULL,       "This is right!"   ,NULL,MB_OK);
MessageBox (NULL,  TEXT("This is right!")  ,NULL,MB_OK);



WinAPI has some weirdness with how it treats strings due to its switch to Unicode several years back. What this means is there are now 3 different character types to use (and 3 different sets of functions to match):

wchar_t strings use the 'W' form of functions like MessageBoxW

char strings use the 'A' form of functions like MessageBoxA

TCHAR strings use the 'normal' form of functions like MessageBox

Plainly, if you are calling MessageBox you need to give it a TCHAR string. "foo" is NOT a TCHAR string (it's a char string) and therefore is incorrect.

I personally recommend that when you are dealing with WinAPI, you try to use wchar_t strings (and therefore the 'W' form of all WinAPI functions and structs) for everything.

If you only have ASCII characters in strings, you can get away with the char / 'A' versions if you don't care about Unicode support.

I highly recommend avoiding TCHAR / 'normal' versions at all costs. I've gone on several rants on why TCHARs are awkward, error prone, and provide no benefit. Here is one such rant, if interested:

http://www.cplusplus.com/forum/windows/105027/#msg566904


It's worth noting that while I use MessageBox as an example here... the concept applies to every WinAPI function which accepts a string as a parameter... and every WinAPI struct which has a string as a member (ie: OPENFILENAMEW)



I realize that to code properly, you might have to break some tough habits. But please make the effort.

Thanks for reading.
Last edited on
Someone in a PM wrote:
Is there any kind of workaround to make the functions behave like they have the W? I've been coding everything in unicode strings to the tchar functions



My first advice would be to shake that habit and start using the correct function call with the correct string type. Typing an extra 'W' is very easy to do.


That said... TCHAR behavior is determined by the UNICODE and _UNICODE macros. If you want TCHAR==char, then make sure both of those macros are undefined. If you want TCHAR==wchar_t, then make sure they're both defined.

In VS, this is done via the "Character Set" project setting. Setting this to "Use Unicode Character Set" will define both macros. I'm unsure what difference between the other two settings is.

In other IDEs, I'm not sure if there's a similar option. But they all have a way to define specific macros prior to compilation. Simply add UNICODE and _UNICODE to that list and it'll work.


Of course... these approaches have the downside of someone else trying to compile your code and getting errors because they have a different setting.

If you want to enforce UNICODE/_UNICODE in the code without relying on a compiler setting... you can #define them manually. Just make sure you do it before you include <windows.h>, as that is the only time it matters:

1
2
3
4
5
#define UNICODE
#define _UNICODE
#include <Windows.h>

// now you know TCHAR==wchar_t 


or...

1
2
3
4
5
6
7
8
9
10
#ifdef UNICODE
#undef UNICODE
#endif
#ifdef _UNICODE
#undef _UNICODE
#endif

#include <Windows.h>

// now you know TCHAR==char 






Though again... just use the right type. It's easier and it always works.
Topic archived. No new replies allowed.