Классические API консоли и виртуальные последовательности терминалов

Мы рекомендуем заменить классические API консоли Windows на последовательности виртуальных терминалов. В этой статье описываются различия между первым и вторым вариантами, а также рассматриваются причины этой рекомендации.

Определения

Под классической контактной зоной API консоли Windows имеется в виду серия функциональных интерфейсов на языке C, помещенных в kernel32.dll и имеющих в имени слово Console.

Последовательности виртуальных терминалов определяются как язык команд, входящий в стандартные потоки ввода и вывода. Последовательности виртуальных терминалов используют непечатаемые escape-символы, чтобы передавать команды, чередуемые с обычным печатаемым текстом.

История

Консоль Windows предоставляет обширную контактную зону API для клиентских приложений командной строки, с помощью которой можно управлять как буфером отображения вывода, так и буфером пользовательского ввода. Однако другие платформы, не относящиеся к Windows, никогда не использовали подход на основе API в среде командной строки, предпочитая последовательности виртуальных терминалов, входящие в стандартные потоки ввода и вывода. (В то время корпорация Майкрософт поддерживала подобное решение в ранних версиях DOS и Windows, предлагая драйвер с именем ANSI.SYS.)

С другой стороны, последовательности виртуальных терминалов (для разных диалектов) отвечают за операции среды командной строки на всех остальных платформах. Эти последовательности возникли из стандарта ECMA и серии расширений от разных поставщиков, начиная с терминалов Digital Equipment Corporation и Tektronix и заканчивая более современными и распространенными терминалами наподобие xterm. В домене последовательностей виртуальных терминалов существует множество расширений, причем одни последовательности поддерживаются значительно шире, чем другие. Можно с уверенностью сказать, что эти последовательности стали мировым стандартом в качестве языка команд для командной строки, чье общеизвестное подмножество поддерживается практически каждым терминалом и клиентским приложением командной строки.

Кроссплатформенная поддержка

Последовательности виртуальных терминалов изначально поддерживаются на разных платформах, благодаря чему приложения для терминала и служебные программы командной строки можно легко переносить между версиями и вариантами операционных систем, за исключением Windows.

Напротив, API консоли Windows поддерживаются только в Windows. Чтобы перенести служебные программы командной строки с одной платформы на другую, на пути между Windows и виртуальным терминалом должен быть создан обширный адаптер или библиотека преобразования.

Удаленный доступ

Последовательности виртуальных терминалов наиболее полезные при использовании удаленного доступа. Они не требуют дополнительных работ для передачи или выполнения удаленных вызовов процедур, которые так необходимы для настройки стандартного подключения удаленной командной строки. Чтобы перенести всю информацию, необходимую приложению, которое сообщает последовательности удаленному узлу, достаточно просто подключить транспортный канал ввода и вывода (или же один двухсторонний канал) через канал, сокет, файл, последовательный порт или любое другое устройство.

API консоли Windows, в свою очередь, доступны только на локальном компьютере, и при любой попытке подключиться к ним удаленно кроме простого канала придется создавать целый промежуточный слой для удаленных вызова и передачи.

Разделение задач

Некоторые API консоли Windows предоставляют низкоуровневый доступ к буферам ввода и вывода или вспомогательные функции для интерактивных командных строк. Сюда могут входить псевдонимы и журнал команд, запрограммированные в подсистеме консоли и среде узла, а не в самом клиентском приложении командной строки.

Другие платформы, напротив, передают ответственность за хранение текущего состояния приложения и за удобство его использования служебной программе командной строки или самой оболочке.

Благодаря тому, как консоль Windows обрабатывает эту обязанность в узле консоли и API, написание приложения с упомянутыми функциями становится легче и быстрее, при этом снимается обязанность запоминания состояния знаков или управления вспомогательными функциями редактирования. Однако из-за этого такие действия практически невозможно удаленно использовать между платформами, версиями или сценариями, поскольку существуют различные варианты реализации и доступности. Этот же способ обработки обязанности делает так, что последнее интерактивное взаимодействие приложений командной строки Windows начинает полностью зависеть от реализации, приоритетов и цикла выпуска узла консоли.

Например, такие расширенные функции редактирования строк, как выделение синтаксиса и комплексные критерии выбора, возможны только в том случае, когда приложение командной строки обрабатывает изменения редактирования самостоятельно. Консоль, в отличие от клиентского приложения, никогда не будет обладать достаточным контекстом для полного понимания этих сценариев.

Другие платформы, в свою очередь, используют последовательности виртуальных терминалов для обработки этих действий и самого взаимодействия между виртуальными терминалами посредством клиентской библиотеки с возможностью повторного использования, например readline и ncurses. Конечный терминал отвечает только за отображение информации и прием входных данных через двухсторонний канал связи.

Команды, которые выполняются в обратном направлении

С помощью консоли Windows некоторые действия можно выполнить в неестественном для потоков ввода и вывода направлении. Это избавляет приложения командной строки Windows от необходимости управления собственными буферами. Кроме того, приложения командной строки Windows получают возможность выполнять расширенные операции, такие как имитация или внедрение входных данных от имени пользователя, а также считывание записей отдельных журналов.

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

Другие платформы, использующие последовательности виртуальных терминалов, не поддерживают это действие. Мы рекомендуем перейти с классической консоли Windows на последовательности виртуальных терминалов, чтобы обеспечить совместимость и безопасность.

Прямой доступ к окну

Контактная зона API консоли Windows предоставляет точный дескриптор окна для окна размещения. Благодаря этому служебная программа командной строки может выполнять дополнительные операции с окном, имея доступ к широкому диапазону API Win32, разрешенных для дескриптора окна. Эти API Win32 способны управлять состоянием окна, его рамкой, значком или другими свойствами.

Для других платформ, которые используют последовательность виртуальных терминалов, также существует небольшой набор команд, которые можно выполнить для окна. Эти команды могут выполнять такие действия, как изменение размера окна или отображаемого заголовка, однако их нужно выполнять в той же полосе и в том же элементе управления, что и остальной поток.

По мере развития Windows увеличивалось количество элементов управления безопасностью и ограничений для дескрипторов окон. Менялись также характер и доступность дескриптора окна в приложении для каждого отдельного элемента пользовательского интерфейса, особенно с увеличением поддержки форм-факторов и платформ устройств. Из-за этого прямой доступ к окну для приложений командной строки становится ненадежным ввиду постоянного развития платформы и ее возможностей.

Unicode

UTF-8 — это кодировка для данных в Юникоде, которую используют почти на всех современных платформах, поскольку она обеспечивает оптимальный баланс между переносимостью, размером хранилища и временем обработки. Однако в Windows в качестве основной кодировки для данных в Юникоде изначально выбрана кодировка UTF-16. Поддержка UTF-8 в Windows становится все более значительной, однако использование этих форматов Юникода не исключает возможности использования других кодировок.

Платформа консоли Windows поддерживала ранее и будет дальше поддерживать все существующие кодовые страницы и кодировки. Используйте UTF-16 для максимальной совместимости между версиями Windows и при необходимости выполняйте алгоритмический перевод с помощью UTF-8. Для консольной системы предусматривается расширенная поддержка UTF-8.

Поддержку UTF-16 можно активировать в консоли, не совершая дополнительных настроек и используя вариант W всех API-интерфейсов консоли. Она является более вероятным выбором для приложений, уже хорошо знакомых с UTF-16 через взаимодействие с wchar_t и вариантом W других функций и продуктов платформы Microsoft и Windows.

Поддержку UTF-8 в консоли можно активировать с помощью варианта A API-интерфейсов консоли для дескрипторов консоли, задав для кодовой страницы значения 65001 или CP_UTF8 с помощью методов SetConsoleOutputCP и SetConsoleCP соответственно. Предварительная настройка кодовых страниц необходима только в том случае, если для компьютера в настройках для приложений, не поддерживающих Юникод, в разделе "Регион" панели управления не выбрано значение Use Unicode UTF-8 for worldwide language support (Использовать Unicode UTF-8 для поддержки всех языков).

Примечание.

На данный момент UTF-8 поддерживается полностью в стандартном потоке вывода при использовании методов WriteConsole и WriteFile. Поддержка потока ввода зависит от режима ввода и будет совершенствоваться с течением времени. Примечательно, что стандартные режимы "обработанного" ввода не полностью поддерживают UTF-8. Текущее состояние этого механизма можно найти на сайте GitHub в разделе microsoft/terminal#7777. Решение проблемы заключается в использовании алгоритмически реализуемого UTF-16 для считывания ввода с помощью методов ReadConsoleW или ReadConsoleInputW, пока не будут решены оставшиеся вопросы.

Рекомендации

При разработке всех новых и текущих приложений в Windows в качестве способа взаимодействия с терминалом рекомендуется использовать последовательности виртуальных терминалов. Это позволит согласовать клиентские приложения командной строки Windows со стилем разработки приложений на других платформах.

Особенности использования API консоли Windows

Для настройки первоначальной среды все еще нужно будет использовать ограниченное подмножество API-интерфейсов консоли Windows. Платформа Windows по-прежнему отличается от других платформ обработкой процессов, сигналов, устройств и кодировок.

  • Управление стандартными дескрипторами процесса будет по-прежнему реализовано с помощью методов GetStdHandle и SetStdHandle.

  • Конфигурация режимов консоли на дескрипторе для использования поддержки последовательности виртуальных терминалов будет обрабатываться с помощью методов GetConsoleMode и SetConsoleMode.

  • Объявление кодовой страницы или UTF-8 осуществляется с помощью методов SetConsoleOutputCP и SetConsoleCP.

  • Для объединения сеансов или выхода из сеанса работы с консольным устройством может потребоваться определенный уровень управления общим процессом и использование методов AllocConsole, AttachConsole и FreeConsole.

  • Передача сигналов и их обработка будет по-прежнему осуществляться с помощью методов SetConsoleCtrlHandler, HandlerRoutine, а также GenerateConsoleCtrlEvent.

  • Обмен данными с дескрипторами консольного приложения можно выполнять с помощью методов WriteConsole и ReadConsole. Они также могут использоваться с помощью сред выполнения языка программирования в формах: — C Runtime (CRT): Stream I/O, например printf, scanf, putc, getc или других уровней функций ввода-вывода. – Стандартная библиотека C++ (STL): объекты iostream, например cout и cin. — среда выполнения .NET: System.Console , например Console.WriteLine.

  • Для приложений, которые должны получать сведения об изменениях размера окна, по-прежнему понадобится использовать метод ReadConsoleInput, чтобы эти сведения содержали ключевые события, поскольку метод ReadConsole не будет принимать их во внимание.

  • Для приложений, выполняющих операции по отрисовке столбцов, сеток или заполнению экрана, поиск размера окна все равно необходимо выполнить с помощью метода GetConsoleScreenBufferInfo. В сеансе псевдоконсоли размеры буфера и окна будут совпадать.

Планы на будущее и псевдоконсоль

Мы не планируем удалять API консоли Windows с платформы.

Напротив, узел консоли Windows предоставил технологию псевдоконсоли для преобразования существующих вызовов приложений командной строки Windows в последовательности виртуальных терминалов и их последующей переадресации в другую среду размещения в удаленном режиме или на другие платформы.

Это преобразование не безупречно. Для него нужно, чтобы окно узла консоли поддерживало смоделированную среду того, что пользователь может увидеть в Windows. Затем реплика этой смоделированной среды проецируется на узел псевдоконсоли. Все вызовы API консоли Windows выполняются в смоделированной среде, чтобы отвечать потребностям устаревшего клиентского приложения командной строки. На окончательный узел распространяются только эффекты.

Поэтому при использовании приложений командной строки, требующих полной совместимости между платформами и поддержки всех новых функций и сценариев как в Windows, так и в других приложениях, рекомендуется перейти на последовательность виртуальных терминалов и настроить архитектуру приложений командной строки в соответствии с требованиями всех платформ.

Дополнительные сведения об этом переходе Windows для приложений командной строки см. в стратегии развития экосистемы.