Поддерживается ли CP_UTF8 кодовая страница для WriteConsoleA / WriteFile?

Есть много примеров, которые люди предлагали использовать трюки, подобные этому, чтобы получить вывод консоли Unicode:

begin
  OldConsoleOutputCP := GetConsoleOutputCP();
  SetConsoleOutputCP(CP_UTF8);
  try
    // Might also use WriteConsoleA, but this has drawbacks with output redirection
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), Utf8Bytes, ...);
  finally
    // We better restore the output CP that was in use before our program started!
    SetConsoleOutputCP(OldConsoleOutputCP);
  end;
end.

Кажется, это работает очень хорошо.

Документация MSDN только упоминает (по крайней мере, насколько мне известно), что вы должны использовать WriteConsoleW для вывода консоли и WriteFileдля перенаправленного вывода. (Вы можете определить, является ли дескриптор дескриптора консоли значением возвращаемого значения GetConsoleModeи аналогичными методами).

Официально ли она поддерживается Microsoft для SetConsoleOutputCP(CP_UT8)вывода текста Unicode на консоль и перенаправленного вывода? Если да, то где это задокументировано?

Я думал, что кодовая страница с несколькими байтами UTF-8 должна использоваться только для функций WideCharToMultiByteи MultiByteToWideCharфункций?

delphi,winapi,unicode,console,delphi-xe7,

1

Ответов: 1


1 принят

Официально ли Microsoft Microsoft поддерживает использование SetConsoleOutputCP (CP_UT8) для вывода текста Unicode на консоль и перенаправленного вывода?

Конечно, это явно не поддерживается, но трудно сказать, что считается «поддерживаемым» здесь. Это область, где документация безнадежна и полностью отсутствует.

На практике возникают серьезные ошибки при WriteFileвводе- выводе, в том числе , когда консоль находится на другом конце, а ее кодовая страница установлена ??на 65001. В общем, API-интерфейсы ввода-вывода Win32 (и подпрограммы MSDCRT stdlib, построенные поверх них) fail, возвращая количество байтов, записанных или прочитанных, которые фактически являются числами символов.

В вашем примере это не имеет значения, потому что вы игнорируете lpNumberOfBytesWrittenoutparam WriteFile, но обычно, когда вы используете символы, отличные от ASCII, неправильные подсчеты приведут к искаженному повторному выходу и зависают, ожидая большего количества данных при попытке чтения ввода.

Это ошибка в консоли (conhost): она имеет специальную поддержку для передачи правильных отсчетов обратно в Windows для двухбайтовых кодовых страниц, которые используются в качестве кодовых страниц по умолчанию для любого языка установки (a € ~ язык для не-Unicode-приложений), но не для других многобайтовых кодировок общего назначения.

Как было связано с @IInpectable, по крайней мере, одна часть Microsoft специально отказалась исправить один видимый аспект этой проблемы, хотя и не бит Microsoft, которому принадлежит первопричина. В любом случае, к сожалению, это не похоже на то, что эта давняя и глубоко разочаровывающая проблема придет в ближайшее время.

// Могу также использовать WriteConsoleA, но у этого есть недостатки с перенаправлением вывода

Да, общий подход заключается в том, чтобы определить, является ли stdout самой консолью (например, использование _isatty) и веткой WriteConsoleWвместо этого в этом случае.

Дельфы, WinAPI, юникод, консоль, Дельфы-xe7,