【问题标题】:How do I convert PWSTR to string in C++?如何在 C++ 中将 PWSTR 转换为字符串?
【发布时间】:2011-09-16 16:58:51
【问题描述】:

我有以下代码:

// 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 转换为字符串?

【问题讨论】:

  • 查看我的答案,了解在多字节和宽字符之间进行转换的一种方法,反之亦然。看看安德烈的另一种方式。请参阅 Praetorian 或 Tomalak Geret'kal 了解您应该做什么。

标签: c++ windows


【解决方案1】:

1。哎呀!

微软says:

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 实际上设置了您给它的指针的值,以指向 it 分配的内存。你的代码有内存泄漏,我最后的 sn-p 巧妙地错误地释放了内存。

让我们通过阅读 the documentation 来解决这个问题:

ppszPath [out]

Type: PWSTR*

当此方法返回时,包含指向以 null 结尾的 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,但正常的 stringstreams 在 char 上工作。

幸运的是,有一个名为 wstringstream 的宽字符变体使用 wchar_t 代替。

(请注意,这意味着您的文字也必须使用 wchar_ts 构建,使用 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));

【讨论】:

  • +1 但wchar_t 数组不会比向量好一点吗? MAX_PATH 也值得一提。没关系,很好的编辑和很好的眼睛CoTaskFreeMem
  • @AJG85:我的回答中没有向量。 SHGetKnownFolderPath 为您分配。
  • 我现在如何将 wstringstream 转换为字符串?实际上,我对 c_str 很感兴趣,因为我使用 stat 的结果,并且可以从字符串中获取 c_str。
  • @rFactor: ss.str() 给你一个std::wstring。你看到这里的模式了吗? :) 有关更多问题,请参阅您最喜欢的 C++ 标准库参考中的 std::wstringstream 文档。
  • @Tomalak 您的代码也有问题 :-) CoTaskMemFree 采用 void 指针,而不是指向 void 指针的指针。
【解决方案2】:

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

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

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

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

【讨论】:

  • 这也会失败。您需要在字符串litteral 前面加上L,如L"..."
  • 你不需要一个宽字符串吗?
  • @André Caron 哎呀,这就是我没有先尝试的结果!固定。
  • 我现在如何将 wstringstream 转换为字符串?实际上,我对 c_str 很感兴趣,因为我将它用于stat
  • 这行不通。 SHGetKnownFolderPath 分配内存并将localAppData 更改为指向它,如果它是一个数组,这将是一个问题。 :)
【解决方案3】:

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

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

还有另一个功能也反过来:

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

【讨论】:

  • 感谢您谋杀我的用户名 :-)
  • 弗洛伊德失误?惊人的两个字母交换可以做什么;-P
【解决方案4】:

您不能将宽字符串“转换”为字符串。原因(除了 2-byte unit VS. 1-byte unit issue)是这个“cast”会模棱两可。

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

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

【讨论】:

  • 大多数其他答案与谷歌搜索该主题的人想要什么无关......谢谢。
【解决方案5】:

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

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

【讨论】:

    猜你喜欢
    • 2013-02-07
    • 2022-10-05
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 2014-01-19
    • 2010-12-15
    相关资源
    最近更新 更多