Tower
Tower

Reputation: 102865

How do I convert PWSTR to string in C++?

I have the following code:

// Fetch Local App Data folder path.
PWSTR localAppData = (PWSTR) malloc(128);
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);

// Find out the absolute path to chrome.exe
stringstream ss;
ss << localAppData << "/Google/Chrome/Application/chrome.exe";

The result of stringstreamer's .str() is 008F6788/Google/Chrome/Application/chrome.exe, which is wrong.

I can't seem to get stringstreamer to work, neither do strcat or wcsncat due to type incompatibilities.

How do I cast this PWSTR to string?

Upvotes: 10

Views: 28394

Answers (5)

Praetorian
Praetorian

Reputation: 109159

PWSTR is a pointer to a wide-character string. You need

// Fetch Local App Data folder path.
PWSTR localAppData = (PWSTR) malloc(128);
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);

wstringstream ss;
ss << localAppData << L"/Google/Chrome/Application/chrome.exe";

Also, malloc argument indicates the number of bytes to allocate, so you're allocating a buffer that can only hold 64 wide characters (including the NULL character). You might want to use malloc( 128 * sizeof(wchar_t) ).

EDIT:
From the documentation for SHGetKnownFolderPath

ppszPath When this method returns, contains the address of a pointer to a null-terminated Unicode string that specifies the path of the known folder. The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree

So you shouldn't be allocating any memory for the last argument for the function.

wchar_t *localAppData = NULL;
::SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);

wstringstream ss;
ss << localAppData << L"/Google/Chrome/Application/chrome.exe";
::CoTaskMemFree(localAppData);

Upvotes: 5

Chengxi Li
Chengxi Li

Reputation: 454

If you don't like widechar and want ansi string badly, try wcstombs or WideCharToMultiByte.

To call SHGetKnownFolderPath, you don't need to allocate memory by yourself, it will cause memory leak.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385204

1. Yuk!

Microsoft says:

typedef wchar_t* LPWSTR, *PWSTR;

So let's get that horrid nonsense out of your testcase, and lose the C rubbish:

// Fetch Local App Data folder path.
wchar_t* localAppData = new wchar_t[128];
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);

stringstream ss;
ss << localAppData << "/Google/Chrome/Application/chrome.exe";

delete[] localAppData;

2. Warning!

There is a serious flaw here.

SHGetKnownFolderPath actually sets the value of the pointer you give it to point to memory that it allocated. Your code has a memory leak, and my last snippet frees the memory subtly wrongly.

Let's fix that by reading the documentation:

ppszPath [out]

Type: PWSTR*

When this method returns, contains the address of a pointer to a null-terminated Unicode string that specifies the path of the known folder. The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree. The returned path does not include a trailing backslash. For example, "C:\Users" is returned rather than "C:\Users\".

// Fetch Local App Data folder path.
wchar_t* localAppData = 0;
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);

stringstream ss;
ss << localAppData << "/Google/Chrome/Application/chrome.exe";

CoTaskMemFree(static_cast<void*>(localAppData));

Now, on with the show.


3. Wide characters

The syntax issue with your code is that localAppData is a wchar_t, but normal stringstreams work on char.

Fortunately, there is a wide-char variant called wstringstream that uses wchar_t instead.

(Note that this means your literal will have to be built out of wchar_ts, too, using the L string literal prefix.)

And now the final code:

// Fetch Local App Data folder path.
wchar_t* localAppData = 0;
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);

wstringstream ss;
ss << localAppData << L"/Google/Chrome/Application/chrome.exe";

CoTaskMemFree(static_cast<void*>(localAppData));

Upvotes: 36

AJG85
AJG85

Reputation: 16197

I like Praetorina'sPraetorian's answer of just using wide string stream but if you want to convert:

char str[128];
wcstombs(str, localAppData, 128);

There is another function which goes the other way around too:

wchar_t wstr[128];
mbstowcs(wstr, "Hello World", 128);

Upvotes: 3

Andr&#233; Caron
Andr&#233; Caron

Reputation: 45224

You cannot "cast" a wide-character string to a string. The reason (other than the 2-byte unit VS. 1-byte unit issue) is that this "cast" would be ambiguous.

What is the source encoding? What is the destination encoding? In this case, the source encoding is likely to be Unicode (shell extensions may return random crap, nothing guarantees that they performed a valid X-to-Unicode conversion if they weren't using Unicode). The destination encoding is likely to be ASCII, although it technically has to match the system's current codepage.

If you want a lossy Unicode-to-ASCII conversion, you can use WideCharToMultiByte().

Upvotes: 2

Related Questions