Skip to main content
GameDev.net gamedev.net
🔒 Locked

Converting from std::string to LPCWSTR

Started by v0dKA Aug 4, 2005 at 12:18 PM 17 replies 19.2k views
Original Post
v0dKA
v0dKA
I'm trying to use FindFirstFile() in my project. The first argument to that function is a LPCWSTR string (for some reason, MSDN and my build log differ on what the first argument is, but I'd rather listen to my compiler). The string I would like to pass as the first argument is stored in std::string in my project, and I need to somehow convert it to LPCWSTR. Any ideas?
.:-v0d[KA]-:. <<>>
Fruny
Fruny
If the string were in a std::wstring, you could directly use std::wstring::c_str(), but since it is in a narrow-character string, you'll need to convert it to wide characters first. Give me five minutes to find out the easiest way to do that.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
SiCrane
SiCrane
You may want to try using the mbstowcs() function. Alternately, it sounds like your project is being compiled with UNICODE defined, you may be able to disable this in your project properties.
v0dKA
v0dKA
Hmmm, still getting errors. Here's what I tried:

std::string b = ...;LPCWSTR a;mbstowcs( a, b.c_str(), b.size() );FindFirstFile( a, ... );


The error happens at mbstowcs():
error C2664: 'mbstowcs' : cannot convert parameter 1 from 'LPCWSTR' to 'wchar_t *'
Conversion loses qualifiers

What did I do wrong?
.:-v0d[KA]-:. <<>>
SiCrane
SiCrane
A LPCWSTR is a pointer to a const wide character string. To use mbstowcs() you need to pass it a pointer to an array of wide characters (wchar_t) to fill with the wide characters that have been converted from the narrow characters.
Fruny
Fruny
I don't think std::string guarantees contiguous storage, so that's the best I can come up with to do the conversion.

std::wstring widen(const std::string& str){   const std::string::size_type size = str.size();   std::vector<wchar_t> vec(size);   typedef std::ctype<wchar_t> facet_t;   facet_t& facet = std::use_locale<facet_t>( std::locale() );   facet.widen( str.data(), str.data() + size, &vec.front() );   return std::wstring( vec.begin(), vec.end() );}FindFirstFile( widen(str).c_str(), ... );
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
v0dKA
v0dKA
All right, that problem was solved. How about this next one:

std::string filename = filedata.cFileName;

The compiler is flagging this line because it can't convert from WCHAR [260] to std::string. I never had this problem until I installed the Beta of VC++ 2005 Express, which seems to really nitpick variable, particularly string, types.

How do I convert from WCHAR to std::string?
.:-v0d[KA]-:. <<>>
SiCrane
SiCrane
The reverse of mbstowcs() is wcstombs(). Again, I'd check your project to see if you can't get your project built with narrow characters. Or just use std::wstring in the first place.
Fruny
Fruny
That's the inverse problem. You have an array of wide characters, so you'll want to use a narrow() function instead of widen().

std::string narrow(const std::wstring& str){   const std::wstring::size_type size = str.size();   std::vector<char> vec(size);   typedef std::ctype<wchar_t> facet_t;   facet_t& facet = std::use_locale<facet_t>( std::locale() );   facet.narrow( str.data(), str.data() + size, &vec.front() );   return std::string( vec.begin(), vec.end() );}


Note that this probably isn't the most efficient code ever...
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
v0dKA
v0dKA
Well, most of my string problems were fixed. Besides narrow and wide, are there other string formats I need to be aware of?

How do most people deal with strings? Back when I used VC++ 6.0, std::string was the solution to all my problems - I simply didn't have to worry about different formats. When I downloaded the Express betas, it complained where 6.0 didn't. It seems to really nitpick different variable types, and to be perfectly honest, it's beginning to annoy me.

std::string has heaps of useful operators and member functions, and I've been using it for years. If a certain function did not accept it as an argument, I would just use the c_str() member function. Ever since I downloaded VC 2005 betas, I have to spend time figuring out how to convert strings for any functions that takes strings as arguments.

So I was thinking, is there a better way to deal with strings? Or is mbstowcs() and wcstombs() (or Fruny's code, though looking at it gives me a headache) enough to get me out of most string problems?
.:-v0d[KA]-:. <<>>
SiCrane
SiCrane
The visual studio beta hasn't complained about strings when MSVC 6 didn't, it changed the variable types of function arguments of some functions on you. FindFirstFile() is actually two different functions FindFirstFileA() and FindFirstFileW(). Under MSVC 2005, when you use FindFirstFile() you get FindFirstFileW(), under MSVC 6 you got FindFirstFileA(). And FindFirstFileW() takes LPCWSTR where FindFirstFileA() took LPCSTR. In older versions of MSVC you could set the Character Set type in the project properties, which would control which function you got. I don't know if its still there in MSVC 2005.
Fruny
Fruny
Quote:
Original post by v0dKA
Well, most of my string problems were fixed. Besides narrow and wide, are there other string formats I need to be aware of?


Well, you have to worry about what character the computer thinks corresponds to a given character code. That's in addition to worrying about how big those character codes are in the first place (hence narrow vs. wide characters) and how they actually are encoded.

Quote:
How do most people deal with strings?


This is a huge can of worms that most English speakers never open, given that English only uses characters in the 32-127 range. And one of us foreigners with accented characters try to use the software they wrote, it all falls apart...

Quote:
So I was thinking, is there a better way to deal with strings?


Learn about internationalization (i18n). Unfortunately, I don't know of any comprehensive tutorial/reference.

Quote:
or Fruny's code, though looking at it gives me a headache


Tsk, come on. I take the size of the string, create a vector of that size, create a ctype locale facet (which is the class that contains the widening/narrowing functions), perform the conversion, reading from the string and writing to the vector, and then build a new string out of the vector's data. The only hoop I had to jump through was to use a vector, because I don't seem to remember that strings guarante contiguous storage, which is what the range version of the widen/narrow functions rely on. You did the same thing with mbstowcs, except you copied to an array and didn't re-build a string object out of it (granted, that was an unnecessary step in solving your problem, but I was shooting for a more general solution).
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Zahlman
Zahlman
Note that if your strings are both "coming from" and "going to" arrays of wide characters, then instead of converting back and forth, you may be better off just using std::wstring instead of std::string in the first place :)
v0dKA
v0dKA
Made a testable version of my program so far, and unfortunately, more problems. Apparently, it's the msbtowcs() that's not working like I want it to. The first argument, the pointer to the result, remains unaltered. The following code block is taken directly from my program, where FILEPATH is a valid std::string:

LPCWSTR lp_wms_filepath;wchar_t* p_wms_filepath = NULL;mbstowcs( p_wms_filepath, FILEPATH.c_str(), FILEPATH.size() );lp_wms_filepath = p_wms_filepath;


FILEPATH.size() returns 51, and FILEPATH.c_str() returns a valid pointer to the string (I checked both of these to make sure). So what's wrong?
.:-v0d[KA]-:. <<>>
Fruny
Fruny
SiCrane told you to pass a pointer to an array... where did you allocate that array?

mbstowcs does not allocate any memory for you. If it did, the parameter would be a wchar_t** or a wchar_t*&, not just a wchar_t*.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
v0dKA
v0dKA
One step closer to working!

Does mbstowcs() write the null terminating character? In the resulting wide character array, I retrieve the correct string, but immediately after, there are some weird characters that shouldn't be there.
.:-v0d[KA]-:. <<>>
v0dKA
v0dKA
Whoops, I see my problem. I didn't allocate the space for the null terminating character:

wcstombs( a, b.c_str(), b.size() );

should be:

wcstombs( a, b.c_str(), b.size() + 1 );

I think all my problems have been solved, be it much more awkwardly then I like. Worrying about wide and narrow character formats may take a while to get used to.
.:-v0d[KA]-:. <<>>
JoshM
JoshM
FindFirstFile is actually a macro. The real functions are FindFirstFileA and FindFirstFileW. The A version is for char/ascii and the W version is for wchar_t. You should be able to directly call FileFirstFileA.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.