Хранение и извлечение строк UTF-8 из файлов ресурсов Windows (RC)

Я создал файл RC, который содержит таблицу строк, я хотел бы использовать некоторые специальные

символы: ö ü ó ú ő ű á é. поэтому я сохраняю строку с кодировкой UTF-8.

Но когда я вызываю свой файл cpp, что-то вроде этого:

LoadString("hu.dll", 12, nn, MAX_PATH);

Я получаю странный результат:

Сообщение об ошибке с неожиданными символами

Как решить эту проблему?


person user1601401    schedule 22.03.2013    source источник
comment
О, другие венгры тоже. Привет. Фиксированный английский для вас (до определенного уровня).   -  person    schedule 23.03.2013
comment
Из того немногого, что я помню о Windows, она изначально не поддерживает UTF8. Это либо какая-то конкретная кодовая страница, либо UTF16. Надеюсь это поможет.   -  person syam    schedule 23.03.2013
comment
Вероятно, он отлично читается в UTF-8. Проблема возникает, когда вы пытаетесь отобразить его в окне. Код Windows ожидает, что он будет в другой кодировке.   -  person Martin York    schedule 23.03.2013
comment
Спасибо за ответ, а как изменить кодировку окна?   -  person user1601401    schedule 23.03.2013
comment
@user1601401 user1601401 вы не меняете кодировку диалога, но вы должны предоставить ему строку, закодированную либо в вашей локальной кодовой странице (API), либо в API UTF16 (W). В любом случае вам нужно преобразовать строку UTF8 во что-то, что Windows может понять.   -  person syam    schedule 23.03.2013
comment
Современные версии rc.exe понимают UTF-8. Вам нужно использовать #pragma code_page(65001) в файле .rc (верхнего уровня). Строковый ресурс будет храниться как UTF-16, поэтому вам нужно убедиться, что вы используете LoadStringW и MessageBoxW (или компилируете с UNICODE).   -  person jamesdlin    schedule 23.03.2013


Ответы (1)


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

Чтобы получить строку UTF-8 для передачи функциям API Windows (включая MessageBox), необходимо использовать MultiByteToWideChar для преобразования из UTF-8 в UTF-16 (то, что Windows называет Unicode или широкими строками). Передача флага CP_UTF8 для первого параметра — это волшебство, которое включает это преобразование. Пример:

std::wstring ConvertUTF8ToUTF16String(const char* pszUtf8String)
{
    // Determine the size required for the destination buffer.
    const int length = MultiByteToWideChar(CP_UTF8,
                                           0,   // no flags required
                                           pszUtf8String,
                                           -1,  // automatically determine length
                                           nullptr,
                                           0);

    // Allocate a buffer of the appropriate length.
    std::wstring utf16String(length, L'\0');

    // Call the function again to do the conversion.
    if (!MultiByteToWideChar(CP_UTF8,
                             0,
                             pszUtf8String,
                             -1,
                             &utf16String[0],
                             length))
    {
        // Uh-oh! Something went wrong.
        // Handle the failure condition, perhaps by throwing an exception.
        // Call the GetLastError() function for additional error information.
        throw std::runtime_error("The MultiByteToWideChar function failed");
    }

    // Return the converted UTF-16 string.
    return utf16String;                    
}

Затем, когда у вас будет широкая строка, вы явно вызовете вариант широкой строки функции MessageBox, MessageBoxW.

Однако, если вам нужно поддерживать только Windows, а не другие платформы, которые повсеместно используют UTF-8, вам, вероятно, будет намного проще придерживаться исключительно строк в кодировке UTF-16. Это собственная кодировка Unicode, которую использует Windows, и вы можете передавать эти типы строк напрямую в любую из функций Windows API. См. мой ответ здесь, чтобы узнать больше о взаимодействии между функциями Windows API и строками. Я рекомендую вам то же самое, что и другому парню:

  • Используйте wchar_t и std::wstring для символов и строк соответственно.
  • Всегда вызывайте W вариантов функций Windows API, включая LoadStringW и MessageBoxW.
  • Убедитесь, что макросы UNICODE и _UNICODE определены либо до включения каких-либо заголовков Windows, либо в настройках сборки вашего проекта.
person Cody Gray    schedule 22.03.2013