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

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

本文关键字:转换 字符串 PWSTR 中将 c++      更新时间:2023-10-16

我有以下代码:

// 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";

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

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

我如何将这个PWSTR转换为字符串?

的趣事!

微软表示:

typedef wchar_t* LPWSTR, *PWSTR;

所以让我们把这些可怕的废话从你的测试用例中去掉,丢掉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。警告!

这里有一个严重的缺陷

SHGetKnownFolderPath实际上设置了你给它的指针的值,指向分配的内存。你的代码有内存泄漏,我的最后一个代码片段微妙地错误地释放了内存。

让我们通过阅读文档来解决这个问题:

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

现在开始表演。


<标题> 3。宽字符

你的代码的语法问题是,localAppData是一个wchar_t,但正常的stringstream s工作在char

幸运的是,有一个叫做wstringstream的宽字符变体,它使用wchar_t来代替。

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

最后的代码是:

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

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

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

编辑:


来自SHGetKnownFolderPath

的文档

ppszPath当此方法返回时,包含指向指定已知文件夹路径的以空结尾的Unicode字符串的指针的地址。调用进程负责通过调用CoTaskMemFree

在不再需要该资源时释放该资源。

所以你不应该为函数的最后一个参数分配任何内存。

wchar_t *localAppData = NULL;
::SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);
wstringstream ss;
ss << localAppData << L"/Google/Chrome/Application/chrome.exe";
::CoTaskMemFree(localAppData);

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

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

还有一个函数也是相反的:

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

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

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

如果你想要一个有损的unicode到ascii的转换,你可以使用WideCharToMultiByte()

如果你不喜欢widechar,想要ansi字符串,试试wcstombs或WideCharToMultiByte。

调用SHGetKnownFolderPath不需要自己分配内存,否则会导致内存泄漏