Std::string в LPCTSTR

Новая версия типичного вопроса о том, как конвертировать из std::string в LPCTSTR.

Чтение из разных сообщений SO я узнал, что должен это сделать:

CreateDirectory(path.c_str(),NULL);

И все же компилятор дает ошибку, потому что cannot convert from const char * to LPCTSTR.

Я пробовал:

CreateDirectory((LPCTSTR)path.c_str(),NULL);

Нет ошибок!

Однако созданная директория (в правильном месте) называется:

D:\\something\\㩄ぜ弲久䅓余屓䱆彄湡敤屲䵉ⴱ㠶ⴰⵃㅇ㉜洰⵭就䥄牃獥汵獴촀췍췍췍췍췍췍췍﷍﷽꯽ꮫꮫꮫﺫﻮﻮ

что не совсем то, что я хотел, как вы можете догадаться...

Так что мне не хватает? Связано ли это с UNICODE/ANSI? Как я могу это решить?

Ответ 1

Ваша проблема заключается в том, что LPCTSTR разрешен wchar_t* или char* в зависимости от того, поддерживает ли ваша сборка unicode (установлен флаг Unicode или нет).

Чтобы явно вызвать версию char*, вызовите CreateDirectoryA().

Ответ 2

Попробуйте посмотреть эту страницу: What-are-TCHAR-WCHAR-LPSTR-LPWSTR-LPCTSTR-etc. Если вы используете MSVC, вы можете установить Unicode для проекта, а LPCSTR "переведено" на const wchar_t *, что несовместимо с const char *

Сделав это: (LPCTSTR)path.c_str(), вы берете два символа из исходной строки и создаете из них одну юникодную букву wchar_t. То, как вы получаете "китайских" персонажей.

Ответ 3

Вы компилируете для Unicode, что означает, что CreateDirectory является псевдонимом для CreateDirectoryW, широкой версии символа. Однако текст в вашей программе закодирован с использованием ANSI. Это означает, что ваша программа не может правильно обрабатывать интернационализацию.

Компилятор сообщает вам, что существует несоответствие между текстовой кодировкой, ожидаемой CreateDirectoryW, и кодировкой текста, которую вы поставляете. Верно, что вы могли бы вызвать CreateDirectoryA для устранения этого неправильного совпадения, но это только увековечит корневую проблему, факт, что вы используете текст ANSI в своей программе.

Итак, лучшим решением является запуск кодирования всего вашего текста как Unicode. Прекратите использование string и начните использовать wstring. Как только вы измените path на wstring, затем

CreateDirectory(path.c_str(),NULL);

является правильным.

Ответ 4

Как этот вопрос появляется, когда вы пытаетесь найти "(std::) string to LPCTSTR"

Здесь способ преобразования & pass std::string as LPCTSTR с использованием wstring

string path_str = "Yay!"; //your string containing path
wstring path_wstr( path_str.begin(), path_str.end() );
//then this should work:
CreateDirectory(path_wstr.c_str(),NULL);

ВАЖНОЕ ЗАМЕЧАНИЕ Адриана МакКарти:

Это нормально, если исходная строка ASCII или если она ANSI и текущая кодовая страница - Windows-1252 (которая очень похожа на Latin-1). Если источником является UTF-8 или другая кодовая страница, то это просто скрывает проблема.

Ответ 5

Используйте CreateDirectoryA вместо этого. CreateDirectory - это макрос, который расширяется до CreateDirectoryA или CreateDirectoryW в зависимости от конфигурации сборки; Они принимают соответственно LPCSTR и LPCWSTR. Если вы знаете, что у вас есть LPCSTR (что вам дает c_str()), используйте первый.

Ответ 6

Другие пояснения верны:

CreateDirectory, как и многие из API окон, на самом деле является макросом, который расширяется до версии "ANSI" или "Wide" в зависимости от того, определена ли UNICODE. Версия ANSI эффективно преобразует однобайтовую строку символов в широкую символьную строку и затем делегирует ее в широкую строку символов.

Однако предложения для вызова CreateDirectoryA напрямую связаны с некоторыми недостатками:

Конверсии, выполняемые API-интерфейсами ANSI, предполагают, что исходная строка кодируется на текущей кодовой странице пользователя. В простых случаях это, вероятно, так. Но во многих реальных кодексах это не так. Таким образом, вы можете получить неправильный тип преобразования, что приведет к ошибкам, которые вы найдете гораздо позже. По крайней мере, плохой тип приводит к ошибкам, которые вы обнаружите сразу.

Лучшее решение - использовать широкие строки (std:: wstring) повсюду и вызвать CreateDirectoryW. Никакое преобразование не идет не так. Никаких приемов не требуется.

Для многих баз кода переписывание всего, чтобы использовать широкие строки, нецелесообразно. Оказывается, есть веские причины сделать прямо противоположное и продолжать использовать std:: strings, но стандартизировать их наличие сохранить текст UTF-8. Затем, когда вам нужно вызвать Windows API, вы конвертируете (не typecast) в UTF-16 и вызываете широкую версию API напрямую. Это дает вам полную преданность ценой совершения нескольких конверсий и некоторых временных буферов. Поскольку эти типы вызовов редко бывают в горячих точках, стоимость обычно не является большой проблемой.

В Windows для преобразования между UTF-8 и UTF-16 вы можете вызывать MultiByteToWideChar/WideCharToMultiByte с кодовой страницей, установленной на CP_UTF8.

Ответ 7

Я долгое время боролся с этим. После довольно много рытья я нашел, что это работает лучше всего; вы можете попробовать следующее:

std::string t = "xyz";
CA2T wt (t.c_str());