New version of the typical question of how to convert from std::string
to LPCTSTR
.
Reading from different SO posts I learnt that I should do th
Use CreateDirectoryA
instead. CreateDirectory
is a macro that expands to either CreateDirectoryA
or CreateDirectoryW
depending on the build configuration; They take respectively LPCSTR
and LPCWSTR
. If you know you have a LPCSTR
(which is what c_str()
gives you), use the first one.
Try to look at this page: What-are-TCHAR-WCHAR-LPSTR-LPWSTR-LPCTSTR-etc. If you are using MSVC, than you may have set Unicode for project and LPCSTR
is "translated" to const wchar_t *
, which is not compatible with const char *
By doing this: (LPCTSTR)path.c_str()
you are taking two chars from original string and create from them one unicode wchar_t letter. Thats way you are getting "chinese" characters.
Your problem here is the fact that LPCTSTR
is resolved to wchar_t*
or char*
based on whether your build supports unicode (unicode flag set or not).
To explicitly call the char*
version, call CreateDirectoryA()
.
The other explanations are correct:
CreateDirectory, like many of the Window APIs, is actually a macro that expands to an "ANSI" or "Wide" version depending on whether UNICODE
is defined. The ANSI version effectively converts the single-byte character string to a wide character string and then delegates to the wide character string version.
However, the suggestions to call CreateDirectoryA directly come with some drawbacks:
The conversions done by the "ANSI" APIs assume that the source string is encoded in the user's current code page. In simple cases, this is likely true. But in lots of real-life code, it's not. So you can end up with the wrong type of conversion, which leads to bugs you'll find much later. At least the bad typecast leads to bugs you find immediately.
A better solution is to use wide strings (std::wstring) throughout, and to call CreateDirectoryW. No conversion to go wrong. No typecasts required.
For many code bases, rewriting everything to use wide strings is not practical. It turns out that there are good reasons to do exactly the opposite and to continue to use std::strings but to standardize on having them hold UTF-8 text. Then, when you have to call a Windows API, you convert (not typecast) to UTF-16 and call the wide version of the API directly. That gives you full fidelity at the cost of a doing a few conversions and some temporary buffers. Since these types of calls are rarely in hot spots, the cost isn't usually a big deal.
On Windows, to convert between UTF-8 and UTF-16, you can call MultiByteToWideChar/WideCharToMultiByte with the code page set to CP_UTF8.
As this question pops up when you try to find "(std::) string to LPCTSTR"
Here's a way how to convert&pass std::string
as LPCTSTR
using wstring
string path_str = "Yay!"; //your string containing path
wstring path_wstr( path_str.begin(), path_str.end() );
//then this should work:
CreateDirectory(path_wstr.c_str(),NULL);
IMPORTANT Note by Adrian McCarthy:
This is fine if the source string is ASCII or if it's ANSI and the current code page is Windows-1252 (which is very similar to Latin-1). If the source is UTF-8 or another code page, then this just hides the problem.
You are compiling for Unicode which means that CreateDirectory
is an alias for CreateDirectoryW
, the wide character version. However, the text in your program is encoded using ANSI. This means that your program cannot handle internationalization properly.
The compiler is telling you that there is a mismatch between the text encoding that CreateDirectoryW
expects, and the text encoding that you are supplying. It's true that you could call CreateDirectoryA
to resolve that mis-match, but that is only going to perpetuate the root problem, the fact that you are using ANSI text in your program.
So, the best solution is to start encoding all your text as Unicode. Stop using string
and start using wstring
. Once you change path
to wstring
then
CreateDirectory(path.c_str(),NULL);
is correct.