Beginning Win32 Convert wchar_t To String?

Mar 4, 2012 at 2:10am
1
2
3
4
5
6
7
8
9
10
11
	//array for profile path
	 wchar_t path[250];

  ExpandEnvironmentStrings(L"%USERPROFILE%",path,250);

  for (int i = 0; i<250; i++)
  {
	 cout<< path[i] << endl;

  }


So if you look at the code above it works but if you look at the output the path character array is just numbers? This makes it useless if I want to use the USERPATH string as a normal string.

Where would one go from here to convert this?

Thanks in advance guys you are amazing.
Mar 4, 2012 at 7:03am
Ok, so here we go again:

1. You are using wchar_t, so you MUST use ExpandEnvironmentStringsW().
2. std::cout doesn't understant wchar_t's just like that. Use std::wcout instead.
3. Use std::wstring instead of std::string.
Mar 4, 2012 at 8:36pm
webJose ExpandEnvironemntStrings did work though? I just use wcout instead of cout so is that bad or does that matter?
Mar 5, 2012 at 3:11am
You'll see the -W error many, many times over many, many forums and tutorials because it happened to work when they were written and tested. But nobody cared to understand why. This same lack of care was exercised over a decade ago when, for instance, winprog.org wrote their tutorial. And what was the end result of that lack of care? That code samples, as they appear in the tutorial now DON'T WORK under new Visual Studio versions.

So long story short: Your code happens to work by mere luck, or coincidence. Your Visual Studio happens to be configured to #define UNICODE by default. But none of use should ever rely on chance when writing good and durable code.

Read my answer here: http://www.cplusplus.com/forum/general/56526/

In your case, you use cout when you should have used wcout. You can make this char-agnostic like this:

1
2
3
4
5
6
7
8
#ifdef UNICODE
#define tcout std::wcout
#else
#define tcout std::cout
#endif

//and then use it like this:
tcout << myTCHARvariable << std::endl;


If you read my reply in that other thread, you should know now that you must NEVER mix data types. In your code sample, you mix a char-agnostic function name (ExpandEnvironmentStrings) with a wide char variable. This worked by good chance, but is an invalid mixture. You either use ExpandEnvironmentStringsW() or you change path's data type to TCHAR.

If you stick to TCHAR and function names without A or W, then you probably need some data types and definitions for the STL. They are very simple and you probably can declare them yourself, but just in case here are a couple of samples (besides the tcout above):

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifdef UNICODE
typedef std::wstring tstring;
typedef std::wostringstream tostringstream;
typedef std::wistringstream tistringstream;
typedef std::wstringstream tstringstream;
//etc...
#else
typedef std::string tstring;
typedef std::ostringstream tostringstream;
typedef std::istringstream tistringstream;
typedef std::stringstream tstringstream;
//etc...
#endif 

Mar 5, 2012 at 3:29am
@webjose,

Why not typedef like this ?
1
2
typedef std::basic_string<TCHAR> tsring;
typedef std::basic_stringstream<TCHAR> tsringstream;


It is more elegant and no need for ifdefs.

Mar 5, 2012 at 3:31am
Perfectly OK and I often use it. It is just that sometimes I forget, especially when I am all hyped about the #ifdef already. But true, that is shorter and what I think I have in my own headers.
Mar 5, 2012 at 5:53am
webjose etc. thanks again for your help. A few things here ok so when I said it worked I meant the only thing I left out was the W in ExpandEnvironmentStringsW to ExpandEnvironmentStrings, but I still used wcout? Is that still just dumb luck that it worked lol? Or did you mean in past tutorials they used cout instead of wcout ???

That said I'm a little confused on this type defined idea of

1
2
typedef std::basic_string<TCHAR> tsring;
typedef std::basic_stringstream<TCHAR> tsringstream;


I understand the preprocessor directives method but this is some kind of template idea with tchars can someone just explain what's going on with that it isn't something I'm familiar with, sorry if that sounds stupid?
Mar 5, 2012 at 6:11am
The std::string data type is simply a typedef of the templated class std::basic_string<>. Specifically:

typedef std::basic_string<char> std::string;

The std::wstring data type is exactly the same, but instead of char it is wchar_t. Therefore, a typedef of the same class using TCHAR automatically converts to std::string or std::wstring depending on the definition of TCHAR, which varies depending on the #definition of UNICODE.

As for cout/wcout. If you have wide chars/strings, use wcout; otherwise use cout.
Topic archived. No new replies allowed.