Проблема с использованием MultiByteToWideChar

Я хотел преобразовать нормальный string в wide string. Для этого я использую функцию MultiByteToWideChar. Но я не добился успеха, используя эту функцию. Вот что я сделал до сих пор.

Пример

string x = "This is c++ not java";
wstring Wstring;
int c =  MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , x.size() , &Wstring , 0 ); 
// The above line produces error which says 'MultiByteToWideChar' : cannot convert parameter 5 from 'std::wstring *' to 'LPWSTR'

Как я могу исправить эту ошибку? И какой должен быть шестой аргумент этой функции? 0 ok?

Ответ 1

Если последний параметр для MultiByteToWideChar равен 0, вы должны передать NULL как тот, который был перед ним. Согласно doc:

Если это значение равно 0, функция возвращает требуемый размер буфера в символах, включая любой завершающий нулевой символ, и не использует буфер lpWideCharStr.

Итак, первый вызов MultiByteToWideChar вернет размер необходимого вам буфера для широкой строки. Затем вы должны получить неконстантный буфер, достаточно большой для размещения широкой строки, и передать его на другой вызов MultiByteToWideChar (на этот раз последним аргументом должен быть фактический размер буфера, а не 0).

Примерный пример:

int wchars_num =  MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , -1, NULL , 0 );
wchar_t* wstr = new wchar_t[wchars_num];
MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , -1, wstr , wchars_num );
// do whatever with wstr
delete[] wstr;

Также обратите внимание на использование -1 в качестве аргумента cbMultiByte - это избавит вас от обращения с завершающими NULL.

Ответ 2

Второй вопрос об этом, сегодня утром!

WideCharToMultiByte() и MultiByteToWideChar() - боль в использовании. Для каждого преобразования требуется два вызова подпрограмм, и вам нужно следить за распределением/освобождением памяти и следить за тем, чтобы строки были правильно завершены. Вам нужна обертка!

У меня есть удобный С++-обертка в моем блоге, здесь, который вы можете использовать.

Здесь сегодня question

Ответ 3

Функция не может взять указатель на строку С++. Он будет ожидать указатель на буфер с широкими символами достаточного размера - вы должны сами выделить этот буфер.

string x = "This is c++ not java";
wstring Wstring;
Wstring.resize(x.size());
int c =  MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , x.size() , &Wstring[0], 0 ); 

Ответ 4

Вы можете попробовать это решение ниже. Я тестировал, он работает, обнаруживает специальные символы (пример: º ä ç á) и работает в Windows XP, Windows 2000 с пакетом обновления 4 и более поздних версиях, Windows 7, 8, 8.1 и 10. Используя std::wstring вместо new wchar_t/delete, мы уменьшаем проблемы с ресурсами утечки, буфером переполнения и поврежденной кучей.

dwFlags было установлено значение MB_ERR_INVALID_CHARS для работы в Windows 2000 с пакетом обновления 4 (SP4) и более поздних версиях (Windows XP). Если этот флаг не установлен, функция тихо удаляет недопустимые коды.

std::wstring ConvertStringToWstring(const std::string &str)
{
    if (str.empty())
    {
        return std::wstring();
    }
    int num_chars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), NULL, 0);
    std::wstring wstrTo;
    if (num_chars)
    {
        wstrTo.resize(num_chars);
        if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), &wstrTo[0], num_chars))
        {
            return wstrTo;
        }
    }
    return std::wstring();
}