Compartilhar via


APIs de console clássico versus sequências de terminais virtuais

Nossa recomendação é substituir a API do Console do Windows clássica com sequências de terminais virtuais. Este artigo descreverá a diferença entre as duas e discutirá os motivos da nossa recomendação.

Definições

A superfície da API do Console do Windows clássica é definida como a série de interfaces funcionais em linguagem C em kernel32.dll com "Console" no nome.

As sequências de terminais virtuais são definidas como uma linguagem de comandos que é inserida nos fluxos de saída padrão e entrada padrão. As sequências de terminais virtuais usam caracteres de escape não imprimíveis para sinalizar comandos intercalados com texto imprimível normal.

Histórico

O Console do Windows fornece uma ampla superfície de API para aplicativos de linha de comando do cliente para manipular o buffer de exibição de saída e o buffer de entrada do usuário. No entanto, outras plataformas que não são do Windows nunca permitiam essa abordagem específica controlada por API para os ambientes de linha de comando deles, optando por usar sequências de terminais virtuais inseridas dentro dos fluxos de saída padrão e de entrada padrão. (Durante um tempo, a Microsoft também deu suporte a esse comportamento nas edições iniciais do DOS e do Windows por meio de um driver chamado ANSI.SYS.)

Por outro lado, sequências de terminais virtuais (em uma variedade de dialetos) orientam as operações do ambiente de linha de comando para todas as outras plataformas. Essas sequências são enraizadas em um ECMA Standard e em uma série de extensões por muitos fornecedores desde os terminais de Corporação de Equipamento Digital e Tektronix até terminais de software mais modernos e comuns, como xterm. Existem muitas extensões no domínio de sequência de terminais virtuais e há um suporte mais amplo para algumas sequências do que para outras, mas é seguro dizer que o mundo foi padronizado como a linguagem de comando para experiências de linha de comando com um subconjunto conhecido que está tendo o suporte de praticamente todos os aplicativos cliente de terminal e de linha de comando.

Suporte multiplataforma

As sequências de terminais virtuais têm suporte nativo entre plataformas, tornando aplicativos de terminal e utilitários de linha de comando facilmente portáteis entre versões e variações de sistemas operacionais, com exceção do Windows.

Por outro lado, só há suporte para APIs do Console do Windows no Windows. Uma biblioteca extensa de adaptador ou de conversão precisa ser escrita entre o Windows e o terminal virtual (ou vice-versa) quando ocorre uma tentativa de portar utilitários de linha de comando de uma plataforma ou outra.

Acesso remoto

As sequências de terminais virtuais têm uma grande vantagem para o acesso remoto. Elas não exigem trabalho adicional para transportar ou executar chamadas de procedimento remoto com relação ao que é necessário para configurar uma conexão de linha de comando remota padrão. A simples conexão de um canal de transporte de entrada e de saída (ou um canal bidirecional) por um pipe, soquete, arquivo, porta serial ou qualquer outro dispositivo é suficiente para transportar completamente todas as informações necessárias para um aplicativo que comunica essas sequências a um host remoto.

Por outro lado, as APIs do Console do Windows só podem ser acessadas no computador local e todos os esforços para transmiti-las remotamente poderiam exigir a criação de uma camada de interface de transporte e de chamada remota completa além de apenas um canal simples.

Separação de interesses

Algumas APIs do Console do Windows fornecem acesso de nível inferior aos buffers de entrada e de saída ou às funções de conveniência para linhas de comando interativas. Isso pode incluir aliases e histórico de comandos programados no subsistema do console e no ambiente de host, em vez de no próprio aplicativo cliente de linha de comando.

Por outro lado, outras plataformas tornam a memória do estado atual do aplicativo e a funcionalidade de conveniência responsabilidade do utilitário de linha de comando ou do próprio shell.

A maneira como o Console do Windows lida com essa responsabilidade no host e na API do console torna mais rápido e fácil escrever um aplicativo de linha de comando com esses recursos, removendo a responsabilidade de memorizar o estado do desenho ou manipular recursos de conveniência de edição. No entanto, isso torna quase impossível conectar essas atividades remotamente entre plataformas, versões ou cenários devido a variações em implementações e disponibilidade. Essa forma de lidar com a responsabilidade também torna a experiência interativa final desses aplicativos de linha de comando do Windows completamente dependente da implementação, das prioridades e do ciclo de lançamento do host do console.

Por exemplo, recursos de edição de linha avançados, como realce de sintaxe e seleção complexa, só são possíveis quando um aplicativo de linha de comando lida com as próprias questões de edição. O console pode nunca ter contexto suficiente para entender totalmente esses cenários de maneira ampla, como o aplicativo cliente pode.

Por outro lado, outras plataformas usam sequências de terminais virtuais para manipular essas atividades e a própria comunicação com o terminal virtual por meio de bibliotecas do lado do cliente reutilizáveis, como readline e ncurses. O terminal final só é responsável por exibir informações e receber entradas por meio desse canal de comunicação bidirecional.

Verbos incorretos

Com o Console do Windows, algumas ações podem ser executadas na direção oposta à natural nos fluxos de entrada e saída. Isso permite que os aplicativos de linha de comando do Windows evitem a preocupação de gerenciar os próprios buffers. Isso também permite que os aplicativos de linha de comando do Windows executem operações avançadas, como simular/injetar a entrada em nome de um usuário ou ler parte do histórico do que foi escrito.

Embora isso forneça um poder adicional aos aplicativos do Windows que operam em um contexto de usuário específico em um computador, também fornece um vetor para cruzar a segurança e níveis de privilégio ou domínios quando usados em determinados cenários. Esses cenários incluem a operação entre contextos no mesmo computador ou entre contextos em outro computador ou ambiente.

Outras plataformas, que usam sequências de terminais virtuais, não permitem essa atividade. A intenção da nossa recomendação de fazer a transição do Console do Windows clássico para as sequências de terminais virtuais é fazer a convergência com essa estratégia para fins de interoperabilidade e de segurança.

Acesso direto à janela

A superfície da API do Console do Windows fornece o identificador de janela exato para a janela de hospedagem. Isso permite que um utilitário de linha de comando execute operações de janela avançadas, alcançando a ampla gama de APIs Win32 permitidas em um identificador de janela. Essas APIs Win32 podem manipular o estado, o quadro e o ícone da janela ou outras propriedades sobre a janela.

Por outro lado, em outras plataformas com sequências de terminais virtuais, há um conjunto restrito de comandos que podem ser executados na janela. Esses comandos podem fazer coisas como alterar o tamanho da janela ou o título exibido, mas eles precisam ser feitos na mesma faixa e no mesmo controle que o restante do fluxo.

Conforme o Windows evoluiu, os controles de segurança e as restrições dos identificadores de janela aumentaram. Além disso, a natureza e a existência de um identificador de janela endereçável por aplicativo em qualquer elemento específico da interface do usuário evoluíram, especialmente com o aumento do suporte de plataformas e fatores forma do dispositivo. Isso torna frágil o acesso direto à janela para aplicativos de linha de comando à medida que a plataforma e as experiências evoluem.

Unicode

O UTF-8 é a codificação aceita para dados Unicode em quase todas as plataformas modernas, pois ele atinge o equilíbrio certo entre portabilidade, tamanho do armazenamento e tempo de processamento. No entanto, o Windows escolheu historicamente o UTF-16 como a codificação principal para dados Unicode. O suporte para UTF-8 está aumentando no Windows e o uso desses formatos Unicode não impede o uso de outras codificações.

A plataforma do Console do Windows deu e continuará dando suporte a todas as páginas de código e codificações existentes. Use o UTF-16 para obter compatibilidade máxima em versões do Windows e execute a conversão de algoritmos com UTF-8, se necessário. O aumento do suporte para UTF-8 está em andamento para o sistema de console.

O suporte a UTF-16 no console pode ser utilizado sem nenhuma configuração adicional por meio da variante W de todas as APIs de console e é uma opção mais provável para aplicativos com conhecimento de UTF-16 por meio da comunicação com a variante wchar_t e W de outras funções e produtos da plataforma Windows e da Microsoft.

O suporte a UTF-8 no console pode ser utilizado por meio da variante A de APIs de Console com relação a identificadores de console após definir a página de código como 65001 ou CP_UTF8 com os métodos SetConsoleOutputCP e SetConsoleCP, conforme apropriado. Definir as páginas de código com antecedência só será necessário se o computador não tiver escolhido "Usar UTF-8 Unicode para suporte a idiomas mundiais" na seção configurações para aplicativos não Unicode na seção Região do Painel de Controle.

Observação

A partir de agora, o UTF-8 tem suporte completo no fluxo de saída padrão com os métodos WriteConsole e WriteFile. O suporte no fluxo de entrada varia dependendo do modo de entrada e continuará aprimorando com o passar do tempo. Notavelmente os modos "cooked" padrão na entrada não dão suporte completo ao UTF-8 ainda. O status atual desse trabalho pode ser encontrado em microsoft/terminal#7777 no GitHub. A solução alternativa é usar o UTF-16 que pode ser convertido de maneira algorítmica para ler a entrada por meio de ReadConsoleW ou ReadConsoleInputW até que os problemas pendentes sejam resolvidos.

Recomendações

Para o desenvolvimento novo e contínuo no Windows, sequências de terminais virtuais são recomendadas como a maneira de interagir com o terminal. Isso fará a convergência de aplicativos cliente de linha de comando do Windows com o estilo de programação de aplicativo em todas as outras plataformas.

Exceções para usar APIs do Console do Windows

Um subconjunto limitado de APIs do Console do Windows ainda é necessário para estabelecer o ambiente inicial. A plataforma Windows ainda é diferente de outras na manipulação de processos, sinais, dispositivos e codificações:

  • Os identificadores padrão de um processo ainda serão controlados com GetStdHandle e SetStdHandle.

  • A configuração dos modos de console em um identificador para aceitar o suporte à Sequência de Terminais Virtuais será manipulada com GetConsoleMode e SetConsoleMode.

  • A declaração da página de código ou do suporte a UTF-8 é realizada com os métodos SetConsoleOutputCP e SetConsoleCP.

  • Algum nível de gerenciamento de processos em geral pode ser necessário com AllocConsole, AttachConsole e FreeConsole para entrar em uma sessão de dispositivo de console ou sair dela.

  • Os sinais e a manipulação de sinais continuarão sendo realizados com SetConsoleCtrlHandler, HandlerRoutine e GenerateConsoleCtrlEvent.

  • A comunicação com os identificadores de dispositivo de console pode ser realizada com WriteConsole e ReadConsole. Eles também podem ser aproveitados por meio dos runtimes de linguagem de programação nas formas de: - C Runtime (CRT): E/S do fluxo como printf, scanf, putc, getc ou outros níveis de funções de E/S. – STL (Biblioteca Padrão) C++: iostream como cout e cin. - Runtime do .NET: System.Console como Console.WriteLine.

  • Os aplicativos que precisam estar cientes das alterações no tamanho da janela ainda precisarão usar ReadConsoleInput para recebê-las de modo intercalado com eventos importantes, já que ReadConsole sozinho as descartará.

  • A localização do tamanho da janela ainda precisa ser realizada com GetConsoleScreenBufferInfo para aplicativos que tentam desenhar colunas e grades ou preencher a exibição. O tamanho da janela e do buffer será correspondente em uma sessão de pseudoconsole.

Planejamento futuro e pseudoconsole

Não há planos para remover as APIs do Console do Windows da plataforma.

Por outro lado, o host do Console do Windows forneceu a tecnologia de pseudoconsole para converter chamadas de aplicativo de linha de comando do Windows existentes em sequências de terminais virtuais e encaminhá-las a outro ambiente de hospedagem remotamente ou entre plataformas.

Essa conversão não é perfeita. Ela requer que a janela do host do console mantenha um ambiente simulado do que o Windows teria exibido para o usuário. Em seguida, ela projeta uma réplica desse ambiente simulado para o host do pseudoconsole. Todas as chamadas à API do Console do Windows são operadas dentro do ambiente simulado para atender às necessidades do aplicativo cliente de linha de comando herdado. Somente os efeitos são propagados para o host final.

Um aplicativo de linha de comando que deseja ter compatibilidade total entre plataformas e suporte completo de todos os novos recursos e cenários no Windows e em outros lugares é, portanto, recomendado para fazer a migração para sequências de terminais virtuais e ajustar a arquitetura de aplicativos de linha de comando para fazer o alinhamento com todas as plataformas.

Mais informações sobre esta transição do Windows para aplicativos de linha de comando podem ser encontradas em nosso roteiro de ecossistema.