Как мне преобразовать PWSTR в строку в C ++? - PullRequest
5 голосов
/ 16 сентября 2011

У меня есть следующий код:

// 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 в строку?

Ответы [ 5 ]

29 голосов
/ 16 сентября 2011

1. Юк!

Microsoft говорит :

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 [out]

Type: PWSTR*

Когда этот метод возвращает, содержит адрес указателя на завершенную нулем строку Юникода, которая указывает путь к известной папке. Вызывающий процесс отвечает за освобождение этого ресурса, если он больше не нужен, вызывая 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 s, используя строковый префикс 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));
4 голосов
/ 16 сентября 2011

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

EDIT:
Из документации на 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);
3 голосов
/ 16 сентября 2011

Мне нравится Преторина Ответ Преториана о простом строковом потоке, но если вы хотите преобразовать:

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

Есть еще одна функция, которая работает наоборот:

wchar_t wstr[128];
mbstowcs(wstr, "Hello World", 128);
1 голос
/ 16 сентября 2011

Вы не можете "привести" строку широких символов к строке. Причина (кроме проблемы с 2-байтовым блоком VS. 1-байтового блока) состоит в том, что это «приведение» будет неоднозначным.

Что такое исходная кодировка? Что такое кодировка назначения? В этом случае исходной кодировкой, вероятно, будет Unicode (расширения оболочки могут возвращать случайное дерьмо, ничто не гарантирует, что они выполнили действительное преобразование X-в-Unicode, если они не использовали Unicode). Кодировка назначения, вероятно, будет ASCII, хотя технически она должна соответствовать текущей кодовой странице системы.

Если вы хотите преобразовать Unicode в ASCII с потерями, вы можете использовать WideCharToMultiByte().

0 голосов
/ 16 сентября 2011

Если вам не нравится widechar и вам не нужна строка ANSI, попробуйте wcstombs или WideCharToMultiByte.

Чтобы вызвать SHGetKnownFolderPath, вам не нужно выделять память самостоятельно, это приведет к утечке памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...