не может преобразовать 'const char*' в 'LPCWSTR {также известный как const wchar_t*}'

Я получаю сообщение об ошибке в своем коде C++, смысл которого я не совсем понимаю. Урезанные биты кода здесь:

RS232Handle=OpenRS232("COM1", 9600);

HANDLE OpenRS232(const char* ComName, DWORD BaudRate)
{
    ComHandle=CreateFile(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}

Я получаю следующую ошибку:

error: cannot convert 'const char*' to 'LPCWSTR {aka const wchar_t*}' for argument '1' to 'void* CreateFileW(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE)'
     ComHandle=CreateFile(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

Код был взят из кода VS, и теперь я использую Qt Creator.

Как я могу решить эту проблему? Спасибо!


person sci-guy    schedule 16.11.2016    source источник
comment
const char * и const wchar_t * не совпадают и не могут быть неявно преобразованы.   -  person Xirema    schedule 16.11.2016


Ответы (4)


Функция Windows CreateFile на самом деле является макросом, который расширяется до одного из:

  • CreateFileA, который принимает путь к файлу типа const char*
  • CreateFileW, который принимает путь к файлу типа const wchar_t*.

(То же самое верно для большинства функций Windows API, принимающих строку.)

Вы объявляете параметр const char* ComName, но, по-видимому, компилируете с определенным UNICODE, поэтому вызывается W версия функции. Автоматического преобразования из const wchar_t* в const char* нет, отсюда и ошибка.

Ваши варианты:

  1. Измените параметр функции на строку UTF-16 (const wchar_t*).
  2. Сохраните параметр char*, но пусть ваша функция явно преобразует его в строку UTF-16 с помощью такой функции, как MultiByteToWideChar.
  3. Явно вызовите CreateFileA вместо CreateFile.
  4. Скомпилируйте свою программу без UNICODE, чтобы макросы расширялись до версий A по умолчанию.
  5. Похитить известного разработчика Microsoft и заставить его читать UTF-8 Everywhere, пока он не согласится, чтобы Windows полностью поддерживала UTF-8 как кодовой страницей «ANSI», что освобождает разработчиков Windows повсюду от этих широкоформатных символов.

Изменить: я не знаю, имело ли место похищение, но в Windows 10 1903 наконец добавлена ​​поддержка для UTF-8 в качестве кодовой страницы ANSI.

person dan04    schedule 16.11.2016
comment
№ 5 не является отдельной опцией, он просто позволяет работать № 2, № 3 и № 4, когда строка содержит расширенные символы. - person Ben Voigt; 16.11.2016
comment
Изменение набора символов в Visual C++ помогло мне... - person Cypher; 08.11.2020

Есть много способов исправить это

  1. Откройте свойства проекта, Общие/Набор символов. Это будет установлено либо в Unicode, либо в многобайтовом наборе символов. Если вы хотите использовать char*, измените Unicode на MBCS. Это преобразует CreateFile в CreateFileW, если указан Unicode, и CreateFileA, если указан MBCS.
  2. Заключите все строки в _T(), например, _T("COM1"). Что это делает, так это компилирует строку как char*, если указан MBCS, wchar_t, если указан unicode
  3. Сделать все строки широкими, добавив префикс L, например, L"COM1"

Обратите внимание, что в некоторых процедурах обработки ошибок строки специально содержат MBCS.

person cup    schedule 16.11.2016

Попробуй это:

RS232Handle=OpenRS232(L"COM1", 9600);

HANDLE OpenRS232(const wchar_t* ComName, DWORD BaudRate)
{
    ComHandle=CreateFileW(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}

В Windows тип wchar_t используется для представления символов в кодировке UTF-16. Это то, что ядро ​​Windows использует внутри, и поэтому современные версии Visual C++ по умолчанию используют функции Unicode. Если вы настаиваете на использовании вместо этого функций ANSI (таким образом возвращаясь к исходному коду), удалите префикс L из строки «COM1» и измените вызов с CreateFileW на CreateFileA.

Большинство функций Windows API, которые имеют дело со строками, имеют как версию W, так и версию A; единственное известное мне исключение — это функция GetProcAddress который всегда принимает строку ANSI независимо от того, работаете ли вы в своем проекте с ANSI или Unicode.

person Govind Parmar    schedule 16.11.2016
comment
Если ваш тип данных жестко запрограммирован как wchar_t*, используйте CreateFileW. Макрос функции CreateFile следует использовать только вместе с макросами типа TCHAR или LPCTSTR. - person Ben Voigt; 16.11.2016
comment
@BenVoigt расширил мой ответ - person Govind Parmar; 16.11.2016

const char* и const wchar_t* — это два разных типа без неявного преобразования между ними. Поэтому вам необходимо выполнить преобразование перед передачей значения функции CreateFile. Взгляните на этот ответ для возможного подхода к преобразованию: https://stackoverflow.com/a/3074785/6710751

В качестве альтернативы вы можете просто использовать функцию CreateFileA вместо CreateFile, как предложил Бен Фойгт.

person Striezel    schedule 16.11.2016
comment
Или просто позвоните CreateFileA, который сделает преобразование для вас. - person Ben Voigt; 16.11.2016
comment
Спасибо за предложение, я добавил это к ответу. - person Striezel; 16.11.2016