Ответ 1
Ваша проблема заключается в том, что LPCTSTR
разрешен wchar_t*
или char*
в зависимости от того, поддерживает ли ваша сборка unicode (установлен флаг Unicode или нет).
Чтобы явно вызвать версию char*
, вызовите CreateDirectoryA()
.
Новая версия типичного вопроса о том, как конвертировать из 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? Как я могу это решить?
Ваша проблема заключается в том, что LPCTSTR
разрешен wchar_t*
или char*
в зависимости от того, поддерживает ли ваша сборка unicode (установлен флаг Unicode или нет).
Чтобы явно вызвать версию char*
, вызовите CreateDirectoryA()
.
Попробуйте посмотреть эту страницу: What-are-TCHAR-WCHAR-LPSTR-LPWSTR-LPCTSTR-etc. Если вы используете MSVC, вы можете установить Unicode для проекта, а LPCSTR
"переведено" на const wchar_t *
, что несовместимо с const char *
Сделав это: (LPCTSTR)path.c_str()
, вы берете два символа из исходной строки и создаете из них одну юникодную букву wchar_t. То, как вы получаете "китайских" персонажей.
Вы компилируете для Unicode, что означает, что CreateDirectory
является псевдонимом для CreateDirectoryW
, широкой версии символа. Однако текст в вашей программе закодирован с использованием ANSI. Это означает, что ваша программа не может правильно обрабатывать интернационализацию.
Компилятор сообщает вам, что существует несоответствие между текстовой кодировкой, ожидаемой CreateDirectoryW
, и кодировкой текста, которую вы поставляете. Верно, что вы могли бы вызвать CreateDirectoryA
для устранения этого неправильного совпадения, но это только увековечит корневую проблему, факт, что вы используете текст ANSI в своей программе.
Итак, лучшим решением является запуск кодирования всего вашего текста как Unicode. Прекратите использование string
и начните использовать wstring
. Как только вы измените path
на wstring
, затем
CreateDirectory(path.c_str(),NULL);
является правильным.
Как этот вопрос появляется, когда вы пытаетесь найти "(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 или другая кодовая страница, то это просто скрывает проблема.
Используйте CreateDirectoryA
вместо этого. CreateDirectory
- это макрос, который расширяется до CreateDirectoryA
или CreateDirectoryW
в зависимости от конфигурации сборки; Они принимают соответственно LPCSTR
и LPCWSTR
. Если вы знаете, что у вас есть LPCSTR
(что вам дает c_str()
), используйте первый.
Другие пояснения верны:
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.
Я долгое время боролся с этим. После довольно много рытья я нашел, что это работает лучше всего; вы можете попробовать следующее:
std::string t = "xyz";
CA2T wt (t.c_str());