char to LPCWSTR CONVERSION

Pages: 12
hi,
i am a beginner at windows programming . i read the following sample code in one of the turtorials from net. I am using visual studio 2010,


#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MessageBox(NULL, "Goodbye, cruel world!", "Note", MB_OK);
return 0;
}


BUT when i type the same thing i get the erroe message:
MessageBoxW:cannot convert parameter2 form const char [9] to LPCWSTR.
This was supposed to be very easy and beginner stuff. But still i am having problem . Please tell me what to do (a little bit in detail , since i am completely new to window programming and this was my first window program ).


thanks , in advance.
thanks , freddie ,
you have been of great help .
i actually got that right , just by changing to Multi-byte.




thank you freddie . your detailed reply was very insightful.
Last edited on
Visual Studio took the route some time back of setting the default character set to wide character. So, you can either do one of two things; 1) Go into project properties and set the character set to 'unset' or Multi-byte; or, 2) Use a wide character WinMain() declaration and all the _T() macros or wide char variables. Welcome to Window Programming!

I'd recommend you change the project properties to asci/multibyte, or what ever it is. That would get you going quicker and with less fuss. Then your tutorial stuff will work as is and you won't have to hack it up.

Also, you could use CodeBlocks. So far they haven't defaulted to unixcode.
1) Go into project properties and set the character set to 'unset' or Multi-byte;


Don't do this.

MessageBox takes TCHARs. If you're not giving it TCHARs, don't use MessageBox.

Good solutions are:

1
2
3
4
5
6
7
8
// 1)  use TCHARs and MessageBox:
MessageBox(NULL, TEXT("Goodbye, cruel world!"), TEXT("Note"), MB_OK);

// 2)  use chars and MessageBoxA:
MessageBoxA(NULL, "Goodbye, cruel world!", "Note", MB_OK);

// 3)  use wchar_ts and MessageBoxW:
MessageBoxW(NULL, L"Goodbye, cruel world!", L"Note", MB_OK);



Do not mix and match. Ever.
+1 to Disch. If you want to be a Windows programmer of any decent kind, you must accept the fact that it uses TCHAR's and related data types. That's how the Windows SDK works, and that's how it must be used.

i am a beginner at windows programming .


The poor feller apparently doesn't know anything about Windows programming, but he wants to start. He apparently has the very first program in that Forger's Win32 Tutorial, which, if I recall, uses Ansi yet. If he understood the whole single byte / wide character issue, he likely wouldn't have asked the question in the first place. All the poor feller wants to do is get the very first program to run. I told him how to do it in the easiest way.

Now, does that mean I'm recommending that he skirt the whole wide character issue and use ansi permanently? No, it doesn't. However, if he follows the advice of Disch and WebJose, what he now has to face is the translation of the whole Forger's tutorial to wide character at a time when he is just learning the fundamentals of Windows Programming. Whereas, if he follows my advice, he'll be able to paste the code from that Forger's tutorial right into Visual Studio, and it will just work 'as is'.
I understand your point, but if you would have said:

The Windows SDK uses TCHAR's instead of regular chars. It's a long story, but you should change your char's to TCHAR's, and enclose all string literals with _T() or TEXT(). This will handle the conversion to Unicode transparently.


That is a short explanation that allows the user to see the issue is deeper, plus it gives immediate solution to the problem. It would be up to the user to find out more about TCHAR and the Windows SDK. Maybe Disch have created an article about that in the Articles section??

Anyway, I just wanted to let the OP know that there was a bigger topic underneath his/her issue and wanted to stress the fact that it must be learned the right way.
Now, does that mean I'm recommending that he skirt the whole wide character issue and use ansi permanently? No, it doesn't.


There's nothing wrong with using ANSI, if you use the ANSI functions (which in this case is MessageBoxA).

However, if he follows the advice of Disch and WebJose, what he now has to face is the translation of the whole Forger's tutorial to wide character at a time when he is just learning the fundamentals of Windows Programming


Bad tutorials are bad tutorials.

My goal is not to help bad tutorials teach people the wrong way to do things. I would hope you don't have that goal either. My goal is to teach them the right way to do things before they get into very bad habits that are difficult to break out of.

Besides, he doesn't need to know the details of TCHARs and wide characters. A very simple solution is to just put 'A' at the end of every WinAPI function. IE: Use MessageBoxA instead of MessageBox.

Whereas, if he follows my advice, he'll be able to paste the code from that Forger's tutorial right into Visual Studio, and it will just work 'as is'.


It's not about "just getting it to compile", it's about learning how to program.

Teach a man to fish etc etc


EDIT:

webJose wrote:
Maybe Disch have created an article about that in the Articles section??


I did, actually:

http://www.cplusplus.com/forum/articles/16820/
Last edited on
I realize my original answer was short and left all the excrutiating details out. I had to do something at the time, and just wanted to get it working for him. I figured there would be follow up questions. After I took care of what I had to do, I wrote up this, which I still might as well post, even though the original poster didn't return...

If UNICODE is defined (it is by default in recent versions of Visual Studio), the following three programs will work....

1st
1
2
3
4
5
6
7
8
9
10
11
12
//This will work because the 'L' character prepended to the character literals causes
//the compiler to both store and interpret the string literals as comprised of 
//unsigned shorts, i.e., UNICODE characters.  Further, the UNICODE define will cause
//the MessageBox symbol to be interpreted as a call to the function MessageBoxW (and
//that function requires wchar_t characters).  
#include <Windows.h>

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MessageBox(NULL,L"Here Is A Message!",L"Title",MB_OK);
 return 0;
}


2nd
1
2
3
4
5
6
7
8
9
10
11
12
//This will work if UNICODE is defined because the _T macro will cause a 'L' to be
//prepended to the string literals.  The added benifit here is that the same program
//will work for ansi.  Note the include for tchar.h.

#include <Windows.h>
#include <tchar.h>

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MessageBox(NULL,_T("Here Is A Message!"),_T("Title"),MB_OK);
 return 0;
}


3rd
1
2
3
4
5
6
7
8
9
10
//This will work if UNICODE is defined because MessageBoxA and MessageBoxW are declared
//irregardless of whether UNICODE is defined or not, and the below program makes a call
//to MessageBoxA, which takes ordinary ansi characters.
#include <Windows.h>

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MessageBoxA(NULL,"Here Is A Message!","Title",MB_OK);
 return 0;
}





If UNICODE is not defined, i.e., in Visual Studio, if you go into 'Project Properties' and set the character set to 'not set' or 'multibyte', the following programs will work...

1st
1
2
3
4
5
6
7
8
9
//This will work because, UNICODE not being defined, MessageBox will be 'macroed' to
//MessageBoxA, which takes single byte characters for the 2nd and 3rd parameters.
#include <Windows.h>

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MessageBox(NULL,"Here Is A Message!","Title",MB_OK);
 return 0;
}


2nd
1
2
3
4
5
6
7
8
9
10
11
//This will work because the pre-processor will simply provide ansi characters and MessageBox will
//be converted to MessageBoxA.  The compiler will get the same code as just above.  Note that this 
//program will work for either UNICODE or ansi
#include <Windows.h>
#include <tchar.h>

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MessageBox(NULL,_T("Here Is A Message!"),_T("Title"),MB_OK);
 return 0;
}


3rd
1
2
3
4
5
6
7
8
9
//This will work irregardless of whether UNICODE is defined.  Its making a call to MessageBoxW,
//and the proper parameters are being supplied for MessageBoxW.
#include <Windows.h>

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MessageBoxW(NULL,L"Here Is A Message!",L"Title",MB_OK);
 return 0;
}
Last edited on
If UNICODE is defined (it is by default in recent versions of Visual Studio), the following three programs will work....


Well this is where I would argue with you. My definition of "works" is different from yours.

This:
MessageBox(NULL,L"Here Is A Message!",L"Title",MB_OK);

is bad, and does not "work" by my standards. Yes it may compile if your settings are just so, but it's a "bad thing" (tm) to do.

Whether or not UNICODE is defined should be immaterial to how you write your program. That's kind of the point. You should write your code so that it will work no matter how that is defined. That way, in the event the need for the define changes in the future for some reason, your program doesn't explode with a 1001 errors.
MessageBox(NULL,_T("Here Is A Message!"),_T("Title"),MB_OK);
Better?
Last edited on

Whether or not UNICODE is defined should be immaterial to how you write your program. That's kind of the point. You should write your code so that it will work no matter how that is defined....


Well, by that line of reasoning it follows that one shouldn't even use the macros that allow for the generic use of the Windows functions, for example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
WINUSERAPI
HWND
WINAPI
CreateWindowExA(
    DWORD dwExStyle,
    LPCSTR lpClassName,
    LPCSTR lpWindowName,
    DWORD dwStyle,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    HWND hWndParent ,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam);
WINUSERAPI
HWND
WINAPI
CreateWindowExW(
    DWORD dwExStyle,
    LPCWSTR lpClassName,
    LPCWSTR lpWindowName,
    DWORD dwStyle,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    HWND hWndParent ,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam);
#ifdef UNICODE
#define CreateWindowEx  CreateWindowExW
#else
#define CreateWindowEx  CreateWindowExA
#endif // !UNICODE 


...and should use the 'A' and 'W' versions specifically (and not tchar.h), and just use the 'L' prefix if using the 'W' functions. The 'L' prefix is I believe a part of the C/C++ languages, whereas I believe the macros in tchar.h aren't (Microsoft specific). So if you want your code to work irregardless of the definition of macros, that's where you end up.
Well, by that line of reasoning it follows that one shouldn't even use the macros that allow for the generic use of the Windows functions,


I don't see how you get that.

The idea here is that TCHAR is its own type. There are 3 functions, one for each char type.

It's very simple:

MessageBoxA -> char
MessageBoxW -> wchar_t
MessageBox -> TCHAR

Whether or not UNICODE is defined makes no difference, the above pairings will work.

Ideally, failing to use a TCHAR for MessageBox should yield a compiler error. It's just that this is a C lib and is therefore not as typesafe/typestrict as a C++ version would be.

The 'L' prefix is I believe a part of the C/C++ languages, whereas I believe the macros in tchar.h aren't (Microsoft specific).


What does that matter? This is WinAPI... of course it's going to be Microsoft specific.

So if you want your code to work irregardless of the definition of macros, that's where you end up.


Yes, that is one way to do it.

As long as you use the correct pairings as illustrated above.
Last edited on
Much ado about nothing, fellas. You all understand the whole paradigm.

The OP understands nothing of it. Beginners just want their program to work. They don't really care WHY it won't work at this point. They just want it to work in order to get some gratification for their efforts.

Give them that, as freddie1 did.

As they progress, the other stuff will come. They will learn. But in the beginning, let them be a beginner.

Spoken by an expert in begnner.
Last edited on
*facepalm*

Much ado about nothing, fellas


I disagree. Teaching bad habits is quite serious. In a way it's harmful because the person then has to go through the extra time/work of breaking those habits. Old habits die hard, as the saying goes.

Besides that, if they "just make it compile", they won't realize that it's a bad habit until halfway through a project where they need to do it the right way. Then it'll be too late and they'll have all these problems in their code that they have to go back and fix.

Spoken by an expert in having to break bad habits.

Give them that, as freddie1 did.


My solution did that. All he has to do is put an 'A' after MessageBox. Nothing could be simpler.
I know a lot of seriously expert Windows programmers who still use Multi-byte as their character set, not just so MessageBox() will work, but for a number of other reasons as well, so to say that one should only use TCHAR when calling MessageBox() just doesn't jibe with some real experts who still call MessageBox() without using TCHAR or Unicode, but who simply override the necessity by setting their project to Multibyte.

So I would hardly consider that a bad habit.

Beginning programmers usually don't want a lesson on programming when they ask a specific question on how they can get their code to work. What they generally want is an answer on how they can get their code to work.

Once I get an answer on how I can get my code to work, then I can go back and see why it didn't work in the first place, and if I want to know more, or don't understand it, and I can always come back and ask that question too.

That's once thing I appreciate on the MSDN C++ board, i.e., that when I ask questions over there they actually answer the question I'm asking without giving me a lecture on the architure of the computer chip or on the philosophy of this as opposed to that. Some people are so expert in programming that they don't have to tell you that they are expert in programming, which happens a lot on these types of boards, although I'm certainly not applying that to anyone in this case.

Telling to OP to use MessageBoxA() was certainly a reasonable answer. But so was freddie1's telling him to switch to multibyte. If he's going to become a serious programmer, he'll take pains to find out why those two things are necessary as he goes further into programming.

Nothing wrong with explanations, but in my view answering the question the poster actually asked, especially with beginners, is better than trying to give him a lesson in stuff that is over his head at this point.
Last edited on
Actually, I should add that I think Disch's first response in showing the differences between the three calls was entirely appropriate and instructive. My issue is one of over-all philosophy in answering beginners, not that helpful info such as Disch provided should never be provided, because I think that post was excellent in its simplicity and demonstration.
I know a lot of seriously expert Windows programmers who still use Multi-byte as their character set, not just so MessageBox() will work, but for a number of other reasons as well, so to say that one should only use TCHAR when calling MessageBox() just doesn't jibe with some real experts who still call MessageBox() without using TCHAR or Unicode, but who simply override the necessity by setting their project to Multibyte.


I wouldn't call them experts. At best I'd call them sloppy experts. They're using WinAPI incorrectly.

All documentation and source code clearly shows that MessageBox does not take chars. It takes TCHARs. I can cite reference after reference that shows this fact.

Besides, there's no reason not to use the functions correctly. The only reason these "experts" are using them that way is because they're stuck in old bad habits that they grew into.

Which furthers my point. Stop people from forming bad habits and it's better for them in the long run.

Telling to OP to use MessageBoxA() was certainly a reasonable answer. But so was freddie1's telling him to switch to multibyte.


The difference is that using MessageBoxA is what works.

Switching to multibyte works by coincidence.

A somewhat comparable (but slightly hyperbolized) example:


The question:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Parent
{
};

struct Child : public Parent
{
};

int main()
{
  Parent* p = new Child;

  // I need to downcast to Child:
  //  Due to previous checks, I know for a fact p points to a Child
  //  so I don't need an RTTI check.

  Child* c = p;  // but this doesn't work?  How can I convert?
}


A good answer:
1
2
// use static_cast:
Child* c = static_cast<Child*>(p);


A bad answer:
1
2
// cast to void* first:
Child* c = (Child*)((void*)p);



The void pointer will "work" in that the code will compile and run properly in this case.

But it works by coincidence. Under different circumstances, the result could be disasterous. Therefore it's bad advice.
Last edited on
Well, I don't know what programs you've written, but I suspect some of the people I'm talking about, who have been programming for more than 30 or 40 years, and who have written commerical programs as well as having been published in peer reviewed literature as experts, would probably fare pretty well against you with regard to programming C/C++, Windows, Assembly, and other languages, since they can easily move back and forth between all of these without batting any eyelash.

Since Bjarne Stroustrup teaches at my alma mater, I have a little insight there, and so when he subverts functions to his own needs, even though the function is not supposed to work that way according to the standard documenation, I would consider him as knowing more than the person who wrote or designed the documentation or the function in the first place, because he not only knows how the function works inside and out, and then some, but he also knows exactly what he wants to do with it.

Because a person uses a function differently than the documentation makes him neither sloppy nor inexpert. It does make those who see him as such as not up to his level of knowledge on such issues, and certainly not able to think outside the box.

It's kind of like a person who's had 20 hours of classroom instruction on how to swing a golf club going out and telling the resident pro that his right elbow should be closer to his body, and his parallel has gone too far beyond horizontal, even though, of course, the 350 yard teel shot he just made right down the middle of the fairway was very nice indeed.
Last edited on
Ok, now I have to interject. I don't care if Bjarne does it, I don't even care if the Pope does it: Bad practice is bad practice.

Your example about Bjarne clearly shows that the guy knows a big fat LOT, no doubt, but it is BAD practice. Why? For the same reason you must avoid using undocumented Windows API, for example: They can change at any moment, and when they do, your program breaks.

The so-called "feature" that Bjarne may have leveraged by using a function in a way that contradicts the documentation is just an invitation for trouble. A year from now that function could be corrected (assuming the "special feature" was produced by a bug) and there goes Bjarne's "amazing" solution down the toilet.
Last edited on
as well as having been published in peer reviewed literature as experts


Fine. They're bona fide experts. I don't dispute it. It was arrogant of me to imply otherwise, you're right.

Being an expert doesn't mean they can't be wrong on this particular point, though.

Back it up with logic. If you (or they) have an answer for this question that doesn't fall under one of the below categories, I will admit defeat:

What reason do you have for choosing to pass a const char* to MessageBox instead of a const TCHAR*?

I propose the only reason for doing so is one of the following:
1) Ignorance of how char/TCHAR work
2) A habit you grew into and never grew out of
3) Too lazy to type the 'A', "and it doesn't matter for this project anyway"
[EDIT] 4) You did it by mistake [/EDIT]
[EDIT] 5) You were instructed to by someone who outranks you at a company [/EDIT]


As far as I know, there is no legitimate reason to call the function in that manner. If I'm wrong, then by all means call me out on it.

I can name (and have named) a few reasons why it's a bad thing to do. So now it's your turn to tell me why it's a good thing to do.
Last edited on
Pages: 12