windows 如何在 C++ 中将 PWSTR 转换为字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7448057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:06:03  来源:igfitidea点击:

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

c++windows

提问by Tower

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.

stringstreamer 的结果.str()008F6788/Google/Chrome/Application/chrome.exe,这是错误的。

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

由于类型不兼容,我似乎无法让 stringstreamer 工作,strcat 或 wcsncat 也不行。

How do I cast this PWSTR to string?

如何将此 PWSTR 转换为字符串?

回答by Lightness Races in Orbit

1. Yuk!

1.呸!

Microsoft says:

微软

typedef wchar_t* LPWSTR, *PWSTR;

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

所以让我们从你的测试用例中去掉那些可怕的废话,并丢掉 C 垃圾:

// 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!

2. 警告!

There is a serious flaw here.

这里有一个严重的缺陷。

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

SHGetKnownFolderPath实际上将您给它的指针的值设置为指向分配的内存。您的代码存在内存泄漏,而我的最后一段代码巧妙地错误地释放了内存。

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\".

ppszPath[出]

Type: PWSTR*

当此方法返回时,包含指向指定已知文件夹路径的以空字符结尾的 Unicode 字符串的指针的地址。一旦不再需要该资源,调用进程负责通过调用 CoTaskMemFree 来释放该资源。返回的路径不包含尾部反斜杠。例如,返回“C:\Users”而不是“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

3. 宽字符

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

您的代码的语法问题是 localAppData 是一个wchar_t,但正常的stringstreams 工作在char.

Fortunately, there is a wide-char variant called wstringstreamthat uses wchar_tinstead.

幸运的是,有一个叫做 Wide-char 的变体wstringstream,可以使用它wchar_t来代替。

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

(请注意,这意味着您的文字也必须wchar_t使用L字符串文字前缀由s构建。)

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));

回答by Praetorian

PWSTRis a pointer to a wide-character string. You need

PWSTR是指向宽字符串的指针。你需要

// 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, mallocargument 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) ).

此外,malloc参数指示要分配的字节数,因此您正在分配一个只能容纳 64 个宽字符(包括 NULL 字符)的缓冲区。您可能想要使用malloc( 128 * sizeof(wchar_t) ).

EDIT:
From the documentation for SHGetKnownFolderPath

编辑:
从文档中SHGetKnownFolderPath

ppszPathWhen 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

ppszPath当此方法返回时,包含指向指定已知文件夹路径的以空字符结尾的 Unicode 字符串的指针的地址。一旦不再需要该资源,调用进程负责通过调用释放该资源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);

回答by AJG85

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

我喜欢Praetorina 的Praetorian 的回答,即只使用宽字符串流,但如果你想转换:

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);

回答by André Caron

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.

您不能将宽字符串“强制转换”为字符串。原因(除了 2 字节单元 VS. 1 字节单元问题)是这种“转换”是不明确的。

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.

什么是源编码?目标编码是什么?在这种情况下,源编码可能是 Unicode(外壳扩展可能会返回随机废话,如果它们不使用 Unicode,则无法保证它们执行有效的 X 到 Unicode 转换)。目标编码可能是 ASCII,尽管它在技术上必须与系统的当前代码页匹配。

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

如果您想要有损 Unicode 到 ASCII 的转换,您可以使用WideCharToMultiByte().

回答by iamsleepy

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

如果您不喜欢widechar 并且非常想要ansi 字符串,请尝试wcstombs 或WideCharToMultiByte。

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

调用SHGetKnownFolderPath,不需要自己分配内存,会造成内存泄漏。