Я использую FreeType2 в одном из моих проектов. Чтобы отобразить письмо, мне нужно предоставить двухбайтовый код символа Unicode. Тем не менее, кодовые символы, которые читает программа, имеют однобайтовый формат ASCII. Это не создает проблем для кодов символов ниже 128 (коды символов совпадают), но остальные 128 не совпадают. Например:
«A» в ASCII — 0x61, «a» в Unicode — 0x0061 — это нормально
«ą» в ASCII — 0xB9, «ą» в Unicode — 0x0105 — совершенно другое
Я пытался использовать функции WinAPI там, но я должен делать что-то не так. Вот пример:
unsigned char szTest1[] = "ąółź"; //ASCII format
wchar_t* wszTest2;
int size = MultiByteToWideChar(CP_UTF8, 0, (char*)szTest1, 4, NULL, 0);
printf("size = %d\n", size);
wszTest2 = new wchar_t[size];
MultiByteToWideChar(CP_UTF8, 0, (char*)szTest1, 4, wszTest2, size);
printf("HEX: %x\n", wszTest2[0]);
delete[] wszTest2;
Я ожидаю создания новой широкой строки без NULL в конце. Тем не менее размер переменная всегда равна 0. Есть идеи, что я делаю не так? Или, может быть, есть более простой способ решить проблему?
CodePage
параметр для MultiByteToWideChar
неправильно. Utf-8 отличается от ASCII. Вы должны использовать CP_ACP
которая сообщает текущую системную кодовую страницу (которая не совпадает с ASCII — см. Различия в форматах Юникод, UTF, ASCII, ANSI)
Размер скорее всего равен нулю, потому что ваша тестовая строка не является допустимой строкой Utf-8.
Почти для всех функций Win32 вы можете вызвать GetLastError () после того, как функции не удастся получить подробный код ошибки, поэтому вызов, который также даст вам более подробную информацию.
«Чистый» набор символов ASCII ограничен диапазоном 0-127 (7 бит). 8-битные символы с установленным старшим значащим битом (т. Е. В диапазоне 128-255) не определены однозначно: их определение зависит от кодовая страница.
Итак, ваш персонаж ą
(ЛАТИНСКОЕ МАЛЕНЬКОЕ ПИСЬМО А С ОГОНЕКОМ) представлен значением 0xB9
в конкретный кодовая страница, которая должна быть Окна-1250. В других кодовых страницах значение 0xB9
связан с разные символ (например, в Кодовая страница Windows 1252, 0xB9
связан с персонажем ¹
, то есть верхний индекс 1).
Чтобы преобразовать символы из определенной кодовой страницы в Unicode UTF-16 с помощью Windows Win32 API, вы можете использовать MultiByteToWideChar
, указав правильную кодовую страницу (которая не CP_UTF8
как написано в коде вашего вопроса; по факту, CP_UTF8
идентифицирует Unicode UTF-8). Вы можете попробовать указать 1250
(ANSI в Центральной Европе; в Центральной Европе (Windows)) идентификатор кодовой страницы.
Если вы можете иметь доступ к АТЛ в своем коде вы можете использовать удобство Вспомогательные классы преобразования строк ATL лайк CA2W
, который оборачивает MultiByteToWideChar(
) распределение вызовов и памяти в классе RAII; например.:
#include <atlconv.h> // ATL String Conversion Helpers
// 'test' is a Unicode UTF-16 string.
// Conversion is done from code-page 1250
// (ANSI Central European; Central European (Windows))
CA2W test("ąółź", 1250);
Теперь вы должны быть в состоянии использовать test
Строка в вашем Unicode API.
Если у вас нет доступа к ATL или вы хотите C ++ STL на основе Решение, вы можете рассмотреть такой код:
///////////////////////////////////////////////////////////////////////////////
//
// Modern STL-based C++ wrapper to Win32's MultiByteToWideChar() C API.
//
// (based on http://code.msdn.microsoft.com/windowsdesktop/C-UTF-8-Conversion-Helpers-22c0a664)
//
///////////////////////////////////////////////////////////////////////////////
#include <exception> // for std::exception
#include <iostream> // for std::cout
#include <ostream> // for std::endl
#include <stdexcept> // for std::runtime_error
#include <string> // for std::string and std::wstring
#include <Windows.h> // Win32 Platform SDK
//-----------------------------------------------------------------------------
// Define an exception class for string conversion error.
//-----------------------------------------------------------------------------
class StringConversionException
: public std::runtime_error
{
public:
// Creates exception with error message and error code.
StringConversionException(const char* message, DWORD error)
: std::runtime_error(message)
, m_error(error)
{}
// Creates exception with error message and error code.
StringConversionException(const std::string& message, DWORD error)
: std::runtime_error(message)
, m_error(error)
{}
// Windows error code.
DWORD Error() const
{
return m_error;
}
private:
DWORD m_error;
};
//-----------------------------------------------------------------------------
// Converts an ANSI/MBCS string to Unicode UTF-16.
// Wraps MultiByteToWideChar() using modern C++ and STL.
// Throws a StringConversionException on error.
//-----------------------------------------------------------------------------
std::wstring ConvertToUTF16(const std::string & source, const UINT codePage)
{
// Fail if an invalid input character is encountered
static const DWORD conversionFlags = MB_ERR_INVALID_CHARS;
// Require size for destination string
const int utf16Length = ::MultiByteToWideChar(
codePage, // code page for the conversion
conversionFlags, // flags
source.c_str(), // source string
source.length(), // length (in chars) of source string
NULL, // unused - no conversion done in this step
0 // request size of destination buffer, in wchar_t's
);
if (utf16Length == 0)
{
const DWORD error = ::GetLastError();
throw StringConversionException(
"MultiByteToWideChar() failed: Can't get length of destination UTF-16 string.",
error);
}
// Allocate room for destination string
std::wstring utf16Text;
utf16Text.resize(utf16Length);
// Convert to Unicode UTF-16
if ( ! ::MultiByteToWideChar(
codePage, // code page for conversion
0, // validation was done in previous call
source.c_str(), // source string
source.length(), // length (in chars) of source string
&utf16Text[0], // destination buffer
utf16Text.length() // size of destination buffer, in wchar_t's
))
{
const DWORD error = ::GetLastError();
throw StringConversionException(
"MultiByteToWideChar() failed: Can't convert to UTF-16 string.",
error);
}
return utf16Text;
}
//-----------------------------------------------------------------------------
// Test.
//-----------------------------------------------------------------------------
int main()
{
// Error codes
static const int exitOk = 0;
static const int exitError = 1;
try
{
// Test input string:
//
// ą - LATIN SMALL LETTER A WITH OGONEK
std::string inText("x - LATIN SMALL LETTER A WITH OGONEK");
inText[0] = 0xB9;
// ANSI Central European; Central European (Windows) code page
static const UINT codePage = 1250;
// Convert to Unicode UTF-16
const std::wstring utf16Text = ConvertToUTF16(inText, codePage);
// Verify conversion.
// ą - LATIN SMALL LETTER A WITH OGONEK
// --> Unicode UTF-16 0x0105
// http://www.fileformat.info/info/unicode/char/105/index.htm
if (utf16Text[0] != 0x0105)
{
throw std::runtime_error("Wrong conversion.");
}
std::cout << "All right." << std::endl;
}
catch (const StringConversionException& e)
{
std::cerr << "*** ERROR:\n";
std::cerr << e.what() << "\n";
std::cerr << "Error code = " << e.Error();
std::cerr << std::endl;
return exitError;
}
catch (const std::exception& e)
{
std::cerr << "*** ERROR:\n";
std::cerr << e.what();
std::cerr << std::endl;
return exitError;
}
return exitOk;
}
///////////////////////////////////////////////////////////////////////////////