CP_UTF8是WriteConsoleA / WriteFile支持的代码页吗?

时间:2016-10-12 10:37:11

标签: delphi winapi unicode console delphi-xe7

many examples人建议使用与此类似的技巧来获取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文档only ever mentions(至少据我所知)您should use WriteConsoleW用于控制台输出,WriteFile用于重定向输出。 (您可以通过GetConsoleMode的返回值和类似方法检测句柄是否是控制台句柄。

Microsoft 正式支持使用SetConsoleOutputCP(CP_UT8)将Unicode文本输出到控制台并重定向输出?如果是,它在哪里记录?

我认为UTF-8多字节代码页只能用于WideCharToMultiByteMultiByteToWideChar函数吗?

1 个答案:

答案 0 :(得分:1)

  

Microsoft正式支持使用SetConsoleOutputCP(CP_UT8)将Unicode文本输出到控制台并重定向输出吗?

当然没有明确支持,但很难说这里的“支持”是什么 - 这是一个文档很差到完全缺失的领域。

实际上,当控制台位于另一端并且其代码页设置为65001时,I / O存在严重错误,包括WriteFile。通常,Win32 I / O API(以及MSVCRT) stdlib例程构建在它们之上)通过返回实际字符​​数的字节数写入或读取计数而失败。

在您的示例中无关紧要,因为您忽略了lpNumberOfBytesWritten的{​​{1}} outparam,但通常在使用非ASCII字符时,错误的计数将导致错误的重复输出和挂起等待有关尝试读取输入的更多数据。

这是控制台(conhost)中的一个错误:它具有特殊情况支持,可以将正确的计数传递回Windows,以获取双字节字符集代码页,这些代码页用作任何安装区域设置的默认代码页( '非Unicode应用程序的语言'),但不适用于其他通用的多字节编码。

@ pnspectable的linked至少有一部分微软特别拒绝解决这个问题的一个可见方面,尽管微软没有根本原因。无论哪种方式,遗憾的是,这种长期存在且令人沮丧的问题不会很快结束。

  

//也可能使用WriteConsoleA,但这有输出重定向的缺点

是的,一种常见的方法是检测stdout是否是自己的控制台(例如使用WriteFile)并转而分支到_isatty