Sign in to follow this  
stenny

L (again) new problem!

Recommended Posts

Hello there, GO TO MY SECOND REPLY TO FIND A NEW PROBLEM I know, that if you're creating a windowsclass, and you name it:
// somewhere in int WINAPI WinMain(...)
wcex.lpszClassName	= "Class";




You need to place an L before it or embrace it with TEXT(), if your in unicode.
// somewhere in int WINAPI WinMain(...)
wcex.lpszClassName	= L"Class";




But what if you use a variable:
// some where in the declarations
const char g_szClass[] = "Class";

// somewhere in int WINAPI WinMain(...)
wcex.lpszClassName	= g_szClass;




I can't place an L before it in the declaration, because it's a char there. And I also can't place it in WinMain, because Lg_szClass is no existing variable. What is the best way to solve this? -Stenny [Edited by - stenny on July 20, 2006 6:42:22 AM]

Share this post


Link to post
Share on other sites
You need to include <tchar.h>

Then, you declare all your chars as TCHAR, put TEXT() or _T() around all of your string constants and you are away.

Good thing about this is it will resolve to the correct form whether UNICODE is on or not.


#include <tchar.h>

const TCHAR *Name=_T("Hello");




HTH Paul

Share this post


Link to post
Share on other sites
@Dhm
Thanks, that worked:


// some where in the declarations
const char g_szClass[] = "Class";

// somewhere in int WINAPI WinMain(...)
wcex.lpszClassName = L" (g_szClass) ";





@EasilyConfused
That worked too, yours is even better. But what if I don't declare the char at the creation, like:


void AppError(BOOL Fatal, char *Text, ...)
{
TCHAR *CaptionText[12];
TCHAR *ErrorText[2048];
va_list valist;

// build the messagebox caption based on fatal flag //
if (Fatal == FALSE)
{
strcpy(CaptionText, "Error");
} else {
strcpy(CaptionText, "Fatal Error");
}

// build the variable text buffer //
va_start(valist, Text);
vsprintf(ErrorText, Text, valist);
va_end(valist);

// Display the messagebox //
MessageBox(NULL, ErrorText, CaptionText, MB_OK | MB_ICONERROR);

// Post a quit message if error was fatal
if (Fatal == TRUE)
{
PostQuitMessage(0);
}
}


This is the complete function

Share this post


Link to post
Share on other sites
Quote:
Original post by stenny
@Dhm
Thanks, that worked:
// some where in the declarations
const char g_szClass[] = "Class";

// somewhere in int WINAPI WinMain(...)
wcex.lpszClassName = L" (g_szClass) ";


Uh...

Now, it don't work. the content of g_szClass[] is not automagically copied into the brand new string (L"(g_szClass)"). This evaluate to a string which contains "(g_szClass)" in unicode.

Quote:
Original post by stenny
@EasilyConfused
That worked too, yours is even better. But what if I don't declare the char at the creation, like:
void AppError(BOOL Fatal, char *Text, ...)
{
TCHAR *CaptionText[12];
TCHAR *ErrorText[2048];
va_list valist;

// build the messagebox caption based on fatal flag //
if (Fatal == FALSE)
{
strcpy(CaptionText, "Error");
} else {
strcpy(CaptionText, "Fatal Error");
}

// build the variable text buffer //
va_start(valist, Text);
vsprintf(ErrorText, Text, valist);
va_end(valist);

// Display the messagebox //
MessageBox(NULL, ErrorText, CaptionText, MB_OK | MB_ICONERROR);

// Post a quit message if error was fatal
if (Fatal == TRUE)
{
PostQuitMessage(0);
}
}


This is the complete function


To work with TCHAR strings, you have to use TCHAR* functions, not the char* C functions. For example, strcpy() is now _tcscpy(). Your code becomes:

void AppError(BOOL Fatal, TCHAR *Text, ...)
{
// be aware that using such kind of code makes your program
// vulnerable to buffer overflow attacks. Moreover, it allocates
// a very big area on the stack (in UNICODE, 4120 bytes)
TCHAR CaptionText[12]; // why did you declared an array of string?
TCHAR ErrorText[2048]; // same question
va_list valist;

// build the messagebox caption based on fatal flag //
if (Fatal == FALSE)
{
_tcscpy(CaptionText, "Error");
} else {
_tcscpy(CaptionText, "Fatal Error");
}

// build the variable text buffer //
va_start(valist, Text);
_vstprintf(ErrorText, Text, valist);
va_end(valist);

// Display the messagebox //
MessageBox(NULL, ErrorText, CaptionText, MB_OK | MB_ICONERROR);

// Post a quit message if error was fatal
if (Fatal == TRUE)
{
PostQuitMessage(0);
}
}





You also have another alternative: go to your project properties, and select the proper characater set (multi-byte vs. unicode). This will undefine the UNICODE macro in your code, meaning that you'll get rid of these L, TEXT() and wide char string stuff. Of course, using TCHAR would still be a must, because it will allow you to do a simple recompile to build eitehr the unicode version of your program or the non-unicode version.

HTH,

Share this post


Link to post
Share on other sites
Sorry Stenny - perhaps I should have mentioned that you can't just then use TCHAR interchangably with char* like that. MSDN has a wealth of information about the compatible function equivalents.

Share this post


Link to post
Share on other sites
@Emmanuel
Uh...

Quote:
Now, it don't work. the content of g_szClass[] is not automagically copied into the brand new string (L"(g_szClass)"). This evaluate to a string which contains "(g_szClass)" in unicode.


It worked though.

Quote:
To work with TCHAR strings, you have to use TCHAR* functions, not the char* C functions. For example, strcpy() is now _tcscpy(). Your code becomes:


Thanks. I know of the other solutions (changing to non-unicode), but that has indeed that disadvantage.

Quote:
Sorry Stenny - perhaps I should have mentioned that you can't just then use TCHAR interchangably with char* like that. MSDN has a wealth of information about the compatible function equivalents.


Thanks, but the AppError needs those functions though. I normally just use char*, but if VS throws up the error (cannot convert from char* to lPCWSTR or something like it), I change it with TCHAR.

-Stenny

EDIT
the array of string? it was an array of chars first.
And if it uses that much memory...is there another way?!

Share this post


Link to post
Share on other sites
Quote:
Original post by stenny
@Emmanuel
Uh...

Quote:
Now, it don't work. the content of g_szClass[] is not automagically copied into the brand new string (L"(g_szClass)"). This evaluate to a string which contains "(g_szClass)" in unicode.


It worked though.

It appeared to work, but it doesn't do what you expect it to do (this is the real definition of "working" [smile]). Your code seems to assume that wcex.lpszClassName will contain "Class" but it contains only "(g_szClass)". If later you want to compare the class name with "Class", the test will fail.

Edit:
Quote:
Original post by stenny
EDIT
the array of string? it was an array of chars first.
And if it uses that much memory...is there another way?!

Yes, using dynamic allocation (or better: if you are programming using C++, you can use a std::vector<> to ease the job).

Regards,

Share this post


Link to post
Share on other sites
ok. So we'll have to scrap that option. Wait...Can't I just create LPCWSTR's from scratch? Like:

const LPCWSTR g_szClass = "Classname";

- Stenny

Share this post


Link to post
Share on other sites
Quote:
Original post by stenny
ok. So we'll have to scrap that option. Wait...Can't I just create LPCWSTR's from scratch? Like:

const LPCWSTR g_szClass = "Classname";

- Stenny


const LPCWSTR g_szClass = L"Classname"; [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by stenny
ok. So we'll have to scrap that option. Wait...Can't I just create LPCWSTR's from scratch? Like:

const LPCWSTR g_szClass = "Classname";

- Stenny


Yes, but you need an 'L' infront to indicate the 'W' in LPCWSTR, meaning "wide" characters.

EDIT: Nevermind, Emmanuel Deloget got it. I should actually refresh the page to see what new replies there are instead of just deciding no one will post before me :).

Share this post


Link to post
Share on other sites
Thanks, but what if I don't declare it from start, like in AppError? I have the same problem here again. I'll try something out.

Quote:
EDIT: Nevermind, Emmanuel Deloget got it. I should actually refresh the page to see what new replies there are instead of just deciding no one will post before me :).


Well, you know what confucius said :P.

-Stenny

Share this post


Link to post
Share on other sites
Sounds to me like you would be better taking M Delagot's suggestion and making a firm decision whether you want to use UNICODE or not through your compiler settings.

If you want to write portable code, but STILL use specific string handling functions, the only way I can see you could do it would be to detect manually whether or not UNICODE was on (by examining a macro, I guess) in your AppError function, then use the conversion functions to create a single-byte version of your string if it was to pass to said functions.

Sounds like a bit of a nightmare to me.

Share this post


Link to post
Share on other sites
Quote:
Original post by stenny
Thanks, but what if I don't declare it from start, like in AppError? I have the same problem here again. I'll try something out.

If you need to convert char to wchar_t, you have to use conversion functions, like dhm said:
Quote:
Original post by dhm
Hi,

Sounds like you need some string conversion functions. Have a look at http://msdn2.microsoft.com/en-US/library/ms235631.aspx for some inspiration.

Cheers,
dhm

This is important ONLY IF you need to convert strings from one type to another type. If you control all the strings in your application, TCHAR is the way to go, and the _T() macro might help:
// (Long) Pointer to a Constant Tchar STRing
LPCTSTR myString = _T("teh string content");


Depending on your setup configuration, you migh need to be able to convert from a LPCTSTR to a LPWSTR (+ back conversion: LPWCSTR to LPTSTR) or from LPCTSTR to LPSTR (+ back conversion: LPCSTR to LPTSTR) [in the previous type names, the L can be forgotten: PSTR, PTSTR, PWSTR, PCSTR, PCTSTR and PCWSTR are aliases to the corresponding types).

#include <windows.h>
#include <tchar.h>
#include <string.h>

// PWSTR is assumed to be already allocated
void tstr2wstr(PCTSTR tstr, PWSTR wstr)
{
#ifdef UNICODE
// really: unicode to unicode; we only need to copy the string
wcscpy(wstr, tstr);
#else
// not in unicode: conversion needed
mbstowcs(wstr, tstr, _tcslen(tstr)+1);
#endif
}

// PTSTR is assumed to be already allocated
void wstr2tstr(PCWSTR wstr, PTSTR tstr)
{
#ifdef UNICODE
// really: unicode to unicode; we only need to copy the string
wcscpy(tstr, wstr);
#else
// not in unicode: conversion needed
wcstombs(tstr, wstr, wcslen(wstr)+1);
#endif
}

// PSTR is assumed to be already allocated
void tstr2str(PCTSTR tstr, PSTR str)
{
#ifdef UNICODE
// in unicode: conversion needed
mbstowcs(str, tstr, _tcslen(tstr)+1);
#else
// not in unicode, no conversion needed
_tcscpy(str, tstr);
#endif
}

// PWSTR is assumed to be already allocated
void str2tstr(PCSTR str, PTSTR tstr)
{
#ifdef UNICODE
// in unicode: conversion needed
wcstombs(tstr, wstr, wcslen(wstr)+1);
#else
// not in unicode, copy the data
_tcscpy(tstr, str);
#endif
}


Direct wchar_t to/from char string is done using wcstombs() or mbstowcs() so I don't need to write these functions again.

Note that wcstombs() fills the destination parameter with a multi-byte string. This is not really a full char* string (some special characters may be encoded using more than one byte on a MB string). However, if you restrict your character set to the ASCII set, you won't have any problem.

HTH,

Share this post


Link to post
Share on other sites
Quote:
Original post by stenny
what are the advantages and disadvantages of unicode or non-unicode then?

-Stenny


* ASCII and extended ASCII is a very limited set of characters. However, it can fully represent the English language as well as a bunch of other languages.

* Unicode is a character set which contains all the characters of the world (ie all the japanese and chines Kanji, as well as everything in the arab and cyrillic alphabet). It is a must have if your application is going to be released world wide, because it is as simple as ASCII (each character is made of two bytes, not one) and very powerfull.

* MBCS (multi-byte character set) is a mixed character set. It contains some characters that may be encoded using two bytes and some characters that may be encoded using only one byte (a particular byte, called the leading byte, signals which character is two byte long). MBCS is rather difficult to use but can help if you must port your very large application to support foreign languages (I did this some years ago with a code base containing 70 MB of code; changing everything to TCHAR or wchar_t would have been too painfull).

Share this post


Link to post
Share on other sites
I'll stay for english for some time I think, and certainly no languages like japanese, arabic or runescript[grin]. Is this the only disadvantage?

-Stenny

Share this post


Link to post
Share on other sites
Quote:
Original post by Emmanuel Deloget
Quote:
Original post by EasilyConfused
... M Delagot's ...

Oh My Gee you mispelled my n4m3!!!!!111one [grin]
BTW you can call me Emmanuel [smile]


Jeez, sorry. I'm normally so careful about this sort of thing. I thought I was being so clever with the 'M'. [grin]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this