#c #winapi #utf-8
#c #winapi #utf-8
Вопрос:
Я пишу текстовый редактор, и у меня возникли некоторые проблемы с сохранением файлов в формате utf-8. У меня есть функция, которая считывает текст из расширенного элемента управления редактированием и записывает его в файл, используя флаг, переданный функции, который зависит от пользовательских настроек. Это может быть utf-16, ascii или utf-8. Оба сегмента записи файлов в формате utf-16 и ascii работают нормально и создают допустимые файлы. Проблема заключается в том, что в следующем блоке кода вызов GetWindowTextLength всегда возвращает 0. Таким образом, в результате ничего не извлекается из окна или не записывается в файл.
HANDLE hFile;
if ((hFile = CreateFile (pstrFileName, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) {
return FALSE;
}
int iLength = 0;
DWORD dwBytesWritten = 0;
switch (encoding) {
/*other text encoding cases*/
case ID_SETTINGS_UTF_8: {
try {
iLength = GetWindowTextLength(hwndEdit); //returns 0
unique_ptr<wchar_t> wide_buf(new wchar_t[iLength 1]);
GetWindowTextW(hwndEdit, wide_buf.get(), iLength 1);
int bytes_needed = WideCharToMultiByte(CP_UTF8, WC_COMPOSITECHECK |
WC_DEFAULTCHAR | WC_NO_BEST_FIT_CHARS, wide_buf.get(), -1,
NULL, 0, NULL, NULL);
unique_ptr<char> utf8_buf(new char[bytes_needed]);
WideCharToMultiByte(CP_UTF8, WC_COMPOSITECHECK |
WC_DEFAULTCHAR | WC_NO_BEST_FIT_CHARS, wide_buf.get(), -1,
utf8_buf.get(), bytes_needed, NULL, NULL);
WriteFile(hFile, utf8_buf.get(), bytes_needed,
amp;dwBytesWritten, NULL);
if (bytes_needed != dwBytesWritten) {
CloseHandle (hFile);
return FALSE;
}
CloseHandle (hFile) ;
return TRUE;
} catch (bad_allocamp; ba) {
UNREFERENCED_PARAMETER(ba);
CloseHandle (hFile);
return FALSE;
}
}
break;
Комментарии:
1. Здесь действительно проблема с дизайном. Вызов
GetWindowTextLength
действительно не должен быть уникальным для кода UTF-8. Вы должны получить текст в формате UTF-16 из окна в общей части. Аналогично,WriteFile
вызов и его обработка ошибок также должны выполняться в обычном коде — в этом тоже нет UTF-8.2. Пара вопросов по устранению неполадок: в случае, когда
GetWindowTextLength()
возвращает 0, если вы передаете буфер разумного размера вGetWindowText()
возвращает ли он что-нибудь?GetLastError()
Сообщает ли что-нибудь интересное (возможно, вызовитеSetLastError(0)
раньше, чтобы попытаться предотвратить чтение устаревшего кода ошибки)?3. Проверьте hwnd рассматриваемой редактуры форматированного текста, убедитесь, что это правильный hwnd в том месте, где вызывается GetWindowTextLength
Ответ №1:
Вы повреждаете кучу. new[]
должно совпадать с delete[]
, не delete
.
Проще просто использовать std::vector
:
std::vector<wchar_t> wide_buf(iLength 1);
//...
std::vectorchar> utf8_buf(bytes_needed);
Комментарии:
1. Теперь я понимаю, что вы говорите об удалении, после более внимательного прочтения unique_ptr. Это решается путем изменения спецификации типа на unique_ptr<wchar_t[]> . Но вызов GetWindowTextLength по-прежнему возвращает 0, когда кодировка помечена как utf-8.
2. Кажется, я вспоминаю, что MSVC6 был терпим к такому злоупотреблению delete
Ответ №2:
Ваше приложение скомпилировано в формате UNICODE или ANSI? (вы используете объявления GetWindowTextLength и GetWindowTextW)
Можете ли вы показать код для ANSI и для UTF-16 (где вы получите правильный результат).