建议将经典 Windows 控制台 API 替换为 虚拟终端序列。 本文将概述这两者之间的差异,并讨论建议的原因。
定义
经典 Windows 控制台 API 图面定义为名称中带有“Console”的 kernel32.dll C 语言功能接口系列。
虚拟终端序列 定义为嵌入标准输入和标准输出流的命令语言。 虚拟终端序列使用不可打印的转义字符来指示与普通可打印文本交错的命令。
历史
Windows 控制台为客户端命令行应用程序提供了广泛的 API 接口,用于操作输出显示缓冲区和用户输入缓冲区。 但是,其他非 Windows 平台从未为命令行环境提供这种特定的 API 驱动方法,而是选择使用嵌入在标准输入和输出流中的虚拟终端序列。 (一段时间,Microsoft通过名为 ANSI.SYS 的驱动程序在早期版本的 DOS 和 Windows 中也支持此行为。
相比之下,虚拟终端序列(以各种方言的形式)驱动其他所有平台的命令行环境操作。 这些序列植根于 ECMA 标准,并在许多供应商的扩展中得以发展,这些扩展可以追溯到数字设备公司和 Tektronix 终端。它们还被用于更现代和更常见的软件终端,如 xterm。 虚拟终端序列域中存在许多扩展,某些序列比其他序列更广受支持。可以说,全球已经将其标准化为命令行体验的通用命令语言,其中一个著名子集几乎被所有终端和命令行客户端应用程序支持。
跨平台支持
虚拟终端序列 在各个平台上原生支持,使终端应用程序和命令行实用程序在操作系统的不同版本和变体之间轻松移植,Windows 除外。
相比之下, Windows 控制台 API 仅在 Windows 上受支持。 尝试从一个平台或另一个平台移植命令行实用工具时,必须在 Windows 和虚拟终端之间编写广泛的适配器或翻译库,反之亦然。
远程访问
虚拟终端序列 具有远程访问的主要优势。 它们无需额外的工作来传输,或对设置标准远程命令行连接所需的操作执行远程过程调用。 只需通过管道、套接字、文件、串行端口或任何其他设备连接出站和入站传输通道(或单个双向通道),就足以完全携带应用程序将这些序列传递给远程主机所需的所有信息。
相反,只能在本地计算机上访问 Windows 控制台 API,所有远程操作都需要构建完整的远程调用和传输接口层,而不仅仅是一个简单的通道。
分离关注点
某些 Windows 控制台 API 为交互式命令行提供对输入和输出缓冲区的低级别访问或便利功能。 这可能包括在控制台子系统和主机环境中编程的别名和命令历史记录,而不是在命令行客户端应用程序本身中。
相比之下, 其他平台 会内存应用程序当前状态,方便功能由命令行实用工具或 shell 本身负责。
在控制台主机和 API 中处理此责任的 Windows 控制台 方式使使用这些功能编写命令行应用程序更快、更轻松,从而消除了记住绘图状态或处理编辑便利功能的责任。 但是,由于实现和可用性的变化,这几乎不可能跨平台、版本或方案远程连接这些活动。 这种处理责任的方式也使这些 Windows 命令行应用程序的最终交互体验完全依赖于主机的实现、优先级和发布周期。
例如,仅当命令行应用程序处理编辑问题本身时,才能使用高级行编辑功能(如语法突出显示和复杂选择)。 系统控制台永远无法像客户端应用程序那样广泛地理解这些情景,因为它缺乏充分的上下文。
相比之下,其他平台使用 虚拟终端序列 通过可重用的客户端库(如 readline 和 ncurses)来处理这些活动和虚拟终端通信本身。 最终终端仅负责通过该双向通信通道显示信息和接收输入。
错误方向谓词
借助 Windows 控制台,某些作可以在输入和输出流上以相反的自然方向执行。 这允许 Windows 命令行应用程序避免管理自己的缓冲区。 它还允许 Windows 命令行应用执行高级作,例如代表用户模拟/注入输入,或读回所写内容的某些历史记录。
虽然这为在单台计算机上的特定用户上下文中运行的 Windows 应用程序提供了额外的功能,但是当在某些情况下使用时,它还提供跨安全性和特权级别或域的矢量。 此类情景包括在同一台计算机上不同上下文之间进行操作,或跨上下文与另一台计算机或环境进行交互。
使用 虚拟终端序列的其他平台不允许此活动。 我们推荐从经典 Windows 控制台过渡到虚拟终端序列,其意图是出于互操作性和安全原因与这一策略趋同。
直接窗口访问
Windows 控制台 API 界面提供确切的窗口句柄给托管窗口。 这样,命令行实用工具就可以通过利用针对窗口句柄允许的广泛的 Win32 API 来执行高级窗口操作。 这些 Win32 API 接口可以操作窗口的状态、框架、图标或其他有关窗口的属性。
相比之下,在其他具有 虚拟终端序列的平台中,可以针对窗口执行一组狭窄的命令。 这些命令可以执行诸如更改窗口大小或显示标题之类的操作,但它们必须与流的其余部分在相同的带和相同的控件下执行。
随着 Windows 的发展,窗口句柄的安全控制和限制也有所增加。 此外,任何特定用户界面元素上应用程序可寻址窗口句柄的性质和存在已经演变,特别是随着设备外形规格和平台的支持的增加。 这使得随着平台和体验的发展,对命令行应用程序的直接窗口访问变得脆弱。
Unicode
UTF-8 是几乎所有新式平台中 Unicode 数据的接受编码,因为它在可移植性、存储大小和处理时间之间达到适当的平衡。 但是,Windows 以前选择 UTF-16 作为 Unicode 数据的主要编码。 在 Windows 中,对 UTF-8 的支持正在增加,并且使用这些 Unicode 格式并不排除其他编码的使用。
Windows 控制台平台受支持,并将继续支持所有现有代码页和编码。 使用 UTF-16 实现跨 Windows 版本的最大兼容性,并在必要时使用 UTF-8 执行算法转换。 控制台系统正在增强对 UTF-8 的支持。
控制台中的 UTF-16 支持可以通过所有控制台 API 的 W 变体直接使用,无需额外配置,对于通过与其他wchar_tMicrosoft 和 Windows 平台函数和产品的 W 变体通信的应用程序来说,这种支持可能是更理想的选择。
将代码页设置为 或 65001 后,可以根据需要使用 CP_UTF8 和 SetConsoleCP 方法, 然后通过控制台 API 的 A 变体对控制台句柄启用 UTF-8 支持。 仅在计算机未在控制面板的“区域”部分中的非 Unicode 应用程序设置中选择“使用 Unicode UTF-8 进行全球语言支持”时,才需要提前设置代码页。
注释
到目前为止,在标准输出流上完全支持 UTF-8,使用 WriteConsole 和 WriteFile 方法。 对输入流的支持因输入模式而异,并将继续随时间推移而改进。 值得注意的是,输入上的默认 “已煮熟” 模式尚不支持 UTF-8。 可在 GitHub 上的 microsoft/terminal#7777 中找到此工作的当前状态。 解决方法是使用算法可翻译的 UTF-16 通过 ReadConsoleW 或 ReadConsoleInputW 读取输入,直到解决未解决的问题。
建议
对于 Windows 上所有新的和正在进行的开发, 建议使用虚拟终端序列 作为与终端交互的方式。 这会将 Windows 命令行客户端应用程序与所有其他平台上的应用程序编程风格融合在一起。
使用 Windows 控制台 API 的异常情况
仍需要有限子集的 Windows 控制台 API 才能建立初始环境。 Windows 平台在处理、信号、设备和编码处理方面仍与其他平台不同:
进程的标准句柄仍将由 GetStdHandle 和 SetStdHandle 控制。
在用于选择启用虚拟终端顺序支持的句柄上配置控制台模式将通过 GetConsoleMode 和 SetConsoleMode 进行处理。
使用 SetConsoleOutputCP 和 SetConsoleCP 方法对代码页或 UTF-8 支持进行声明。
AllocConsole、AttachConsole 和 FreeConsole 可能需要某种级别的整体进程管理才能加入或离开控制台设备会话。
将继续使用 SetConsoleCtrlHandler、 HandlerRoutine 和 GenerateConsoleCtrlEvent 执行信号和信号处理。
可以使用 WriteConsole 和 ReadConsole 与控制台设备句柄进行通信。 这些也可以通过编程语言运行时来利用:- C 运行时(CRT):流 I/O,如 printf、scanf、putc、getc,或其他级别的 I/O 函数。 - C++标准库 (STL): iostream ,如 cout 和 cin。 - .NET 运行时: System.Console ,如 Console.WriteLine。
必须了解窗口大小更改的应用程序仍将需要使用 ReadConsoleInput 接收与键事件交错的信息,因为仅 ReadConsole 会将其丢弃。
对于尝试绘制列、网格或填充显示的应用程序,仍必须使用 GetConsoleScreenBufferInfo 来查找窗口大小。 窗口和缓冲区大小将在 伪console 会话中匹配。
未来的规划和伪控制台
没有从平台中删除 Windows 控制台 API 的计划。
相反,Windows 控制台主机提供了 伪控制台 技术,用于将现有的 Windows 命令行应用程序调用转换为虚拟终端序列,并将它们远程转发或跨平台转发到另一个托管环境。
此翻译并不完美。 它需要控制台主机窗口来维护 Windows 向用户显示的内容的模拟环境。 然后,它将此模拟环境的副本投影到 伪控制台 主机。 所有 Windows 控制台 API 调用都在模拟环境中运行,以满足旧版命令行客户端应用程序的需求。 仅将效果传播到最终主机。
因此,建议将命令行应用程序迁移到虚拟终端序列并调整命令行应用程序的体系结构,使其与所有平台保持一致,从而跨平台实现完全兼容性,并完全支持 Windows 和其他地方的所有新功能和方案。
有关此命令行应用程序的 Windows 转换的详细信息,请参阅 我们的生态系统路线图。