Conozca la pseudo consola de Windows (ConPTY)

Artículo publicado el 2 de agosto de 2018

Este es el segundo artículo sobre la línea de comandos de Windows, donde discutiremos la nueva infraestructura y las interfaces de programación de la pseudo-consola Windows, es decir, la Pseudo Consola de Windows (ConPTY): por qué la desarrollamos, para qué sirve, cómo funciona, cómo usarla y mucho más.

En el último artículo "El grave legado del pasado. Problemas con la línea de comandos de Windows ” , hablamos sobre los requisitos previos para la aparición del terminal y la evolución de la línea de comandos en Windows, y también comenzamos a estudiar la estructura interna de la consola de Windows y la infraestructura de la línea de comandos de Windows. También discutimos las muchas ventajas y desventajas principales de la consola de Windows.

Uno de los inconvenientes es que Windows está tratando de ser "útil", pero interfiere con los desarrolladores de consolas alternativas y de terceros, desarrolladores de servicios, etc. Al crear una consola o servicio, los desarrolladores deben tener acceso a los canales de comunicación a través de los cuales su terminal / servicio intercambia datos con aplicaciones de línea de comandos, o proporcionarles acceso. En el mundo * NIX, esto no es un problema porque * NIX proporciona una infraestructura de pseudo-terminal (PTY) que facilita la creación de canales de comunicación para una consola o servicio. Pero en Windows no era ...

... hasta ahora!

De TTY a PTY


Antes de contar en detalle sobre nuestro desarrollo, regresemos brevemente al desarrollo de terminales.

Al principio era TTY


Como se discutió en un artículo anterior , en los primeros días de la informática, los usuarios controlaban las computadoras utilizando teletipos electromecánicos (TTY) conectados a una computadora a través de algún tipo de canal de comunicación en serie (generalmente a través de un circuito de corriente de 20 mA ).


Ken Thompson y Dennis Ritchie (de pie) trabajan en el teletipo DEC PDP-11 (mensajes sin pantalla electrónica)

Distribución terminal


Los teletipos fueron reemplazados por terminales computarizados con pantallas electrónicas (generalmente pantallas CRT). Por lo general, los terminales son dispositivos muy simples (de ahí el término "terminal tonto"), que contienen solo la electrónica y la potencia de procesamiento necesaria para las siguientes tareas:

  1. Recepción de entrada de texto desde el teclado.
  2. Almacenar el texto ingresado en una línea (incluida la edición local antes del envío).
  3. Enviar / recibir texto en un canal en serie (generalmente a través de la interfaz RS-232, una vez ubicua).
  4. Visualización del texto recibido en la pantalla del terminal.

A pesar de su simplicidad (o quizás gracias a él), los terminales se convirtieron rápidamente en el principal medio para administrar minicomputadoras, mainframes y servidores: la mayoría de los operadores de entrada de datos, operadores de computadoras, administradores de sistemas, científicos, investigadores, desarrolladores de software y luminarias de la industria trabajaban en terminales DEC, IBM, Wyse y muchos otros.


Almirante Grace Hopper en su oficina con un terminal DEC VT220 en su escritorio

Distribución de terminales de software.


Desde mediados de la década de 1980, en lugar de terminales especializadas, las computadoras de uso general han comenzado a usarse gradualmente, y se han vuelto más asequibles, populares y potentes. Muchas de las primeras PC y otras computadoras de los años 80 tenían aplicaciones terminales que abrían la conexión RS-232 a la PC e intercambiaban datos con cualquier persona en el otro extremo de la conexión.

A medida que las computadoras de uso general se volvieron más sofisticadas, apareció una interfaz gráfica de usuario (GUI) y un mundo completamente nuevo de aplicaciones concurrentes, incluidas aplicaciones de terminal.

Pero había un problema: ¿cómo puede interactuar una aplicación de terminal con otra aplicación de línea de comandos que se ejecuta en la misma máquina? ¿Y cómo conectar físicamente un cable serial entre dos aplicaciones que se ejecutan en la misma computadora?

Apariencia pseudo terminal (PTY)


En el mundo * NIX, el problema se resolvió mediante la introducción de un pseudo terminal (PTY) .

PTY emula equipos de telecomunicaciones en serie en una computadora al exponer los pseudodispositivos maestro y esclavo ("maestro" y "esclavo"): las aplicaciones de terminal se conectan al pseudodispositivo maestro y las aplicaciones de línea de comandos (por ejemplo, shells como cmd, PowerShell y bash) se conectan al pseudodispositivo esclavo. Cuando un cliente terminal transmite comandos de texto y / o control (codificados como texto) al pseudodispositivo maestro, el texto se traduce al esclavo asociado con él. El texto de la aplicación se envía al pseudodispositivo esclavo, luego de regreso al maestro y, por lo tanto, al terminal. Los datos siempre se envían / ​​reciben de forma asincrónica.


Aplicación de pseudo terminal / Shell

Es importante tener en cuenta que el pseudodispositivo "esclavo" emula el comportamiento del terminal físico y convierte los caracteres del comando en señales POSIX. Por ejemplo, si el usuario ingresa CTRL + C en el terminal, el valor ASCII para CTRL + C (0x03) se envía a través del maestro. Cuando se recibe en un pseudodispositivo esclavo, el valor 0x03 se elimina del flujo de entrada y se genera una señal SIGINT .

Dicha infraestructura PTY es ampliamente utilizada por aplicaciones de terminal * NIX, administradores de paneles de texto (por ejemplo, pantalla, tmux), etc. Estas aplicaciones llaman a openpty() , que devuelve un par de descriptores de archivo (fd) para el maestro y esclavo PTY. Luego, la aplicación puede bifurcar / ejecutar una aplicación secundaria de línea de comandos (por ejemplo, bash), que usa sus esclavos fd para escuchar y devolver texto al terminal conectado.

Este mecanismo permite que las aplicaciones de terminal "hablen" directamente con las aplicaciones de línea de comandos que se ejecutan localmente, tal como un terminal hablaría con una computadora remota a través de una conexión en serie / red.

¿Qué, no pseudo-consola de Windows?


Como discutimos en el artículo anterior, si bien la consola de Windows es conceptualmente similar al terminal tradicional * NIX, difiere en varias formas clave, especialmente en los niveles más bajos, lo que puede causar problemas para los desarrolladores de aplicaciones de línea de comandos de Windows, terminales / consolas y servidores de terceros aplicaciones:

  1. Windows no tiene la infraestructura PTY : cuando un usuario inicia una aplicación de línea de comandos (por ejemplo, Cmd, PowerShell, wsl, ipconfig, etc.), el propio Windows "conecta" una instancia de consola nueva o existente a la aplicación.
  2. Windows interfiere con las consolas y aplicaciones de servidor de terceros : Windows (actualmente) no brinda a los terminales una forma de proporcionar canales de comunicación a través de los cuales desean interactuar con una aplicación de línea de comandos. ¡Los terminales de terceros tienen que crear consolas fuera de la pantalla, enviar datos ingresados ​​por el usuario allí y desechar la salida redibujándola en la pantalla de la consola de terceros!
  3. Solo Windows tiene la API de consola : las aplicaciones de línea de comandos de Windows dependen de la API de Win32 Consol, que reduce la portabilidad del código, ya que todas las demás plataformas admiten texto / VT, no la API.
  4. Acceso remoto no estándar : la dependencia de las aplicaciones de línea de comandos de la API de Consol complica significativamente la interacción y los scripts de acceso remoto.

Que hacer


Muchos, muchos desarrolladores a menudo solicitaron un mecanismo similar a PTY en Windows, especialmente aquellos que trabajan con ConEmu / Cmder, Console2 / ConsoleZ, Hyper, VSCode, Visual Studio, WSL, Docker y OpenSSH.

Incluso Peter Bright, editor de tecnología de Ars Technica, me pidió que implementara el mecanismo PTY unos días después cuando comencé a trabajar en el equipo de la consola:



Y recientemente nuevamente:



Bueno, finalmente lo hicimos: creamos una pseudo-consola para Windows :

Bienvenido a la Pseudo Consola de Windows (ConPTY)


Desde la formación del Equipo de consola hace unos cuatro años, el grupo se ha dedicado a la revisión de la consola de Windows y los mecanismos internos de la línea de comando. Al mismo tiempo, consideramos regularmente y cuidadosamente los problemas descritos anteriormente y muchos otros problemas y problemas relacionados. Pero la infraestructura y el código no estaban listos para hacer posible el lanzamiento de la pseudo-consola ... ¡hasta ahora!

La nueva infraestructura de pseudo-consola de Windows (ConPTY), API y algunos otros cambios relacionados eliminarán / aliviarán toda una clase de problemas ... ¡ sin romper la compatibilidad con las aplicaciones de línea de comandos existentes !

La nueva API Win32 ConPTY (la documentación oficial se publicará pronto) ahora está disponible en las últimas compilaciones internas de Windows 10 y el correspondiente SDK de Windows 10 Insider Preview . Aparecerán en la próxima versión principal de Windows 10 (en algún momento del otoño / invierno de 2018).

Consola / ConHost Architecture


Para comprender ConPTY, debe estudiar la arquitectura de la consola de Windows, o más bien ... ¡ConHost!

Es importante comprender que, aunque ConHost implementa todo lo que ve y conoce como una aplicación de consola de Windows, ¡ConHost también contiene e implementa la mayor parte de la infraestructura de línea de comandos de Windows! ¡A partir de ahora, ConHost se convierte en un verdadero "nodo de consola" , que admite todas las aplicaciones de línea de comandos y / o aplicaciones GUI que interactúan con las aplicaciones de línea de comandos!

Como? Por qué Que? Echemos un vistazo más de cerca.

Aquí hay una vista de alto nivel de la arquitectura interna de la consola / ConHost:



En comparación con la arquitectura del artículo anterior , ConHost ahora contiene varios módulos adicionales para el procesamiento de TV y el nuevo módulo ConPTY que implementa API abiertas:

  • API ConPTY : Las nuevas API Win32 ConPTY proporcionan un mecanismo similar al modelo POSIX PTY, pero en la refracción de Windows.
  • Interactividad VT : recibe texto de entrada en codificación UTF-8, convierte cada carácter de texto mostrado en el registro INPUT_RECORD correspondiente y lo guarda en el búfer de entrada. También procesa secuencias de escape, como 0x03 (CTRL + C), convirtiéndolas en KEY_EVENT_RECORDS , que producen la acción de escape adecuada.
  • Renderizador de VT : genera secuencias de VT necesarias para mover el cursor y representar texto y estilo en áreas del búfer de salida que han cambiado desde el fotograma anterior.

OK, pero ¿qué significa realmente?

¿Cómo funcionan las aplicaciones de línea de comandos de Windows?


Para comprender mejor el impacto de la nueva infraestructura ConPTY, echemos un vistazo a cómo la consola de Windows y las aplicaciones de línea de comandos han funcionado hasta ahora.

Cada vez que un usuario inicia una aplicación de línea de comandos como Cmd, PowerShell o ssh, Windows crea un nuevo proceso Win32 en el que carga el binario ejecutable de la aplicación y cualquier dependencia (recursos o bibliotecas).

Un proceso recién creado generalmente hereda los descriptores stdin y stdout de su padre. Si el proceso principal era un proceso de GUI de Windows, entonces faltan los descriptores stdin y stdout, por lo que Windows implementará y adjuntará la nueva aplicación a la nueva instancia de la consola. La comunicación entre las aplicaciones de línea de comandos y su consola se transmite a través de ConDrv.

Por ejemplo, al comenzar desde una instancia de PowerShell sin privilegios elevados, el nuevo proceso de aplicación heredará los descriptores primarios stdin / stdout y, por lo tanto, recibirá datos de entrada y enviará la salida a la misma consola que el padre.

Aquí tenemos que hacer una reserva, ya que en algunos casos las aplicaciones de línea de comandos se lanzan adjuntas a una nueva instancia de la consola, especialmente por razones de seguridad, pero la descripción anterior suele ser cierta.

Finalmente, cuando se inicia la aplicación de línea de comandos / shell, Windows la conecta a la instancia de la consola (ConHost.exe) a través de ConDrv:



¿Cómo funciona ConHost?


Cada vez que se ejecuta una aplicación de línea de comandos, Windows conecta la aplicación a una instancia nueva o existente de ConHost. La aplicación y su instancia de consola están conectadas a través del controlador de consola en modo kernel (ConDrv), que envía / recibe mensajes IOCTL que contienen solicitudes de llamadas API serializadas y / o datos de texto.

Históricamente, como se indicó en un artículo anterior, el trabajo de ConHost es relativamente simple hoy en día:

  • El usuario genera información desde el teclado / mouse / bolígrafo / panel táctil, que se convierte a KEY_EVENT_RECORD o MOUSE_EVENT_RECORD y se almacena en el búfer de entrada.
  • El búfer de entrada se vacía un registro a la vez, realizando las acciones de entrada solicitadas, como mostrar texto en la pantalla, mover el cursor, copiar / pegar texto, etc. Muchas de estas acciones cambian el contenido del búfer de salida. Estas áreas cambiadas son registradas por el motor de estado ConHost.
  • En cada cuadro, la consola muestra las áreas cambiadas del búfer de salida.

Cuando la aplicación de línea de comandos llama a la API de la consola de Windows, las llamadas a la API se serializan en mensajes IOCTL y se envían a través del controlador ConDrv. Luego entrega mensajes IOCTL a la consola adjunta, que decodifica y ejecuta la llamada API solicitada. Los valores devueltos / de salida se vuelven a serializar al mensaje IOCTL y se envían de vuelta a la aplicación a través de ConDrv.

ConHost: contribuyendo al pasado para el futuro


Microsoft se esfuerza por mantener la compatibilidad con las aplicaciones y herramientas existentes siempre que sea posible. Especialmente para la línea de comando. De hecho, las versiones de 32 bits de Windows 10 aún pueden ejecutar muchas / la mayoría de las aplicaciones y ejecutables Win16 de 16 bits.

Como se mencionó anteriormente, una de las funciones clave de ConHost es proporcionar servicios a sus aplicaciones de línea de comandos, especialmente las aplicaciones heredadas que invocan y dependen de la API de la consola Win32. Ahora ConHost ofrece nuevos servicios:

  • Infraestructura sin costuras tipo PTY para la comunicación con consolas y terminales modernas
  • Actualización de aplicaciones de línea de comandos tradicionales / heredadas
    • Recibir y convertir texto UTF-8 / VT para ingresar registros (como si los hubiera ingresado el usuario)
    • Consola API llama a la aplicación alojada, actualizando su búfer de salida en consecuencia
    • Mostrar áreas modificadas del búfer de salida en codificación UTF-8, texto / VT

El siguiente es un ejemplo de cómo una aplicación de consola moderna se comunica con una aplicación de línea de comandos a través de ConPTY ConHost.



En este nuevo modelo:

  1. Consola:
    1. Crea canales de comunicación propios.
    2. Llama a la API de ConPTY para crear ConPTY, lo que obliga a Windows a ejecutar una instancia de ConHost conectada al otro extremo de los canales
    3. Crea una instancia de una aplicación de línea de comandos (por ejemplo, PowerShell) conectada a ConHost, como de costumbre
  2. Conhost:
    1. Lee el texto UTF-8 / VT en la entrada y lo convierte en registros INPUT_RECORD , que se envían a la aplicación de línea de comando
    2. Realizar llamadas API desde una aplicación de línea de comandos que puede modificar el contenido del búfer de salida
    3. Muestra los cambios en el búfer de salida en la codificación UTF-8 (texto / VT) y envía el texto recibido a su consola
  3. Aplicación de línea de comando:
    1. Funciona como de costumbre, lee la entrada y llama a la API de la consola, ¡sin tener idea de que su ConPTY ConHost traduce la entrada y salida de / a UTF-8!

¡El último momento es importante! Cuando la antigua aplicación de línea de comandos usa llamadas a la API de la consola como WriteConsoleOutput(...) , el texto especificado se escribe en el búfer de salida ConHost correspondiente. Periódicamente, ConHost muestra las áreas cambiadas del búfer de salida como texto / VT, que se envía a través de stdout a la consola.

En última instancia, ¡incluso las aplicaciones de línea de comandos tradicionales desde el exterior "hablan" el texto / VT sin ningún cambio !

Usando la nueva infraestructura ConPTY, las consolas de terceros ahora pueden interactuar directamente con aplicaciones de línea de comandos modernas y tradicionales e intercambiarlas todas en texto / VT.

Interactuando remotamente con las aplicaciones de línea de comandos de Windows


El mecanismo descrito anteriormente funciona bien en una computadora, pero también ayuda al interactuar, por ejemplo, con una instancia de PowerShell en una computadora remota de Windows o en un contenedor.

Hay un problema al iniciar una aplicación de línea de comandos de forma remota (es decir, en computadoras remotas, servidores o contenedores). El hecho es que las aplicaciones de línea de comandos en máquinas remotas se comunican con la instancia local de ConHost, porque los mensajes IOCTL no están diseñados para transmitirse a través de la red. ¿Cómo transferir la entrada de la consola local a la máquina remota y cómo obtener la salida de la aplicación que se ejecuta allí? Además, ¿qué hacer con las máquinas Mac y Linux, donde hay terminales pero no hay consolas compatibles con Windows?

Por lo tanto, para controlar de forma remota la máquina Windows, necesitamos algún tipo de agente de comunicación que pueda serializar datos de manera transparente a través de la red, administrar la vida útil de la instancia de la aplicación, etc.

Tal vez algo como ssh ?

Afortunadamente, OpenSSH se portó recientemente a Windows y se agregó como una opción adicional a Windows 10 . PowerShell Core también usa ssh como uno de los protocolos remotos compatibles de PowerShell Core Remoting . Y para aquellos que ejecutan Windows PowerShell, la comunicación remota de Windows PowerShell todavía es una opción aceptable.

Veamos cómo OpenSSH para Windows ahora le permite controlar de forma remota los shells de Windows y las aplicaciones de línea de comandos:



OpenSSH actualmente incluye algunas complicaciones no deseadas:

  1. Usuario:
    1. Inicia el cliente ssh y Windows conecta la instancia de la consola como de costumbre.
    2. Introduce texto en la consola, que envía pulsaciones de teclas al cliente ssh
  2. cliente ssh:
    1. Lee la entrada como bytes de datos de texto
    2. Envía datos de texto a través de la red al servicio de escucha sshd
  3. El servicio sshd pasa por varias etapas:
    1. Inicia el shell predeterminado (por ejemplo, Cmd), que obliga a Windows a crear y conectar una nueva instancia de la consola.
    2. Encuentra y se conecta a la consola de la instancia de Cmd
    3. Mueve la consola fuera de la pantalla (y / o la oculta)
    4. Envía la entrada recibida del cliente ssh a la consola fuera de la pantalla como entrada
  4. La instancia de cmd funciona como siempre:
    1. Recopila información del servicio sshd
    2. El trabajo
    3. Llama a la API de la consola para representar / diseñar texto, mover el cursor, etc.
  5. Consola adjunta [fuera de pantalla]:
    1. Realice llamadas de API actualizando el búfer de salida.
  6. Servicio sshd:
    1. Desecha el búfer de salida de la consola fuera de la pantalla, encuentra las diferencias, las codifica en texto / VT y las envía de vuelta ...
  7. Un cliente ssh que envía texto ...
  8. Consola que muestra texto

Diversión, verdad? ¡Para nada! En esta situación, muchas cosas pueden salir mal, especialmente en el proceso de simular y enviar la entrada del usuario y vaciar el búfer de salida de una consola fuera de la pantalla. Esto conduce a la inestabilidad, bloqueos, corrupción de datos, consumo excesivo de energía, etc. Además, no todas las aplicaciones hacen el trabajo de eliminar no solo el texto en sí, sino también sus propiedades, ¡por eso se pierden el formato y el color!

Trabajo remoto utilizando ConHost y ConPTY modernos


¿Seguramente podemos mejorar la situación? Sí, por supuesto que podemos, hagamos algunos cambios arquitectónicos y apliquemos nuestro nuevo ConPTY:



El diagrama muestra que el circuito ha cambiado de la siguiente manera:

  1. Usuario:
    1. Inicia el cliente ssh y Windows conecta la instancia de la consola como de costumbre.
    2. Introduce texto en la consola, que envía pulsaciones de teclas al cliente ssh
  2. cliente ssh:
    1. Lee la entrada como bytes de datos de texto
    2. Envía datos de texto a través de la red al servicio de escucha sshd
  3. Servicio sshd:
    1. Crea canales stdin / stdout
    2. Llama a la API de ConPTY para iniciar ConPTY
    3. Inicia una instancia de Cmd conectada al otro extremo de ConPTY. Windows inicia y monta una nueva instancia de ConHost
  4. La instancia de cmd funciona como siempre:
    1. Recopila información del servicio sshd
    2. El trabajo
    3. Llama a la API de la consola para representar / diseñar texto, mover el cursor, etc.
  5. Instancia ConPTY ConHost:
    1. Realice llamadas de API actualizando el búfer de salida.
    2. Muestra las regiones modificadas del búfer de salida como texto / VT codificado UTF-8, que se envía de vuelta a la consola / terminal a través de ssh

Este enfoque utilizando ConPTY es claramente más limpio y simple para el servicio sshd. Las llamadas a la API de la consola de Windows se realizan completamente en la instancia de ConHost de la aplicación de línea de comandos, que convierte todos los cambios visibles en texto / VT. Quien se conecta a ConHost, no necesita saber que la aplicación allí llama a la API de la consola, ¡y no genera texto / VT!

Acuerde que este nuevo mecanismo de comunicación remota ConPTY conduce a una arquitectura elegante, consistente y simple. En combinación con las potentes funciones integradas en ConHost, el soporte para aplicaciones más antiguas y la visualización de cambios de las aplicaciones que llaman a las API de consola de la consola como texto / VT, la nueva infraestructura ConHost y ConPTY nos ayuda a mover el pasado hacia el futuro.

API de ConPTY y cómo usarlo


ConPTY API está disponible en la versión actual de Windows 10 Insider Preview SDK .

Por ahora, estoy seguro de que no puedes esperar para ver algún código;)

Echa un vistazo a las declaraciones de API:

 // Creates a "Pseudo Console" (ConPTY). HRESULT WINAPI CreatePseudoConsole( _In_ COORD size, // ConPty Dimensions _In_ HANDLE hInput, // ConPty Input _In_ HANDLE hOutput, // ConPty Output _In_ DWORD dwFlags, // ConPty Flags _Out_ HPCON* phPC); // ConPty Reference // Resizes the given ConPTY to the specified size, in characters. HRESULT WINAPI ResizePseudoConsole(_In_ HPCON hPC, _In_ COORD size); // Closes the ConPTY and all associated handles. Client applications attached // to the ConPTY will also terminated. VOID WINAPI ClosePseudoConsole(_In_ HPCON hPC); 

El API ConPTY anterior expone esencialmente tres nuevas funciones para su uso:

  • CreatePseudoConsole(size, hInput, hOutput, dwFlags, phPC)
    • Crea pty con dimensión en columnas w y líneas h , utilizando canales creados por la persona que llama:
      • size : ancho y alto (en caracteres) del búfer ConPTY
      • hInput : para escribir datos de entrada en PTY como secuencias de texto / VT en codificación UTF-8
      • hOutput : para leer la salida de PTY como secuencias de texto / VT en codificación UTF-8
      • dwFlags : valores posibles:
        • PSEUDOCONSOLE_INHERIT_CURSOR : el PSEUDOCONSOLE_INHERIT_CURSOR creado intentará heredar la posición del cursor de la aplicación de terminal principal
      • phPC : manejador de consola generado por ConPty
    • Devoluciones : éxito / fracaso. Si tiene éxito, phPC contiene el identificador de la nueva ConPty

    ResizePseudoConsole(hPC, size)
    • Cambia el tamaño del búfer interno ConPTY para mostrar un ancho y alto específicos

    ClosePseudoConsole (hPC)
    • ConPTY . , ConPTY, , ,

    ConPTY API


    ConPTY API ConPTY.

    : GitHub

      // Note: Most error checking removed for brevity. // ... // Initializes the specified startup info struct with the required properties and // updates its thread attribute list with the specified ConPTY handle HRESULT InitializeStartupInfoAttachedToConPTY(STARTUPINFOEX* siEx, HPCON hPC) { HRESULT hr = E_UNEXPECTED; size_t size; siEx->StartupInfo.cb = sizeof(STARTUPINFOEX); // Create the appropriately sized thread attribute list InitializeProcThreadAttributeList(NULL, 1, 0, &size); std::unique_ptr<BYTE[]> attrList = std::make_unique<BYTE[]>(size); // Set startup info's attribute list & initialize it siEx->lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>( attrList.get()); bool fSuccess = InitializeProcThreadAttributeList( siEx->lpAttributeList, 1, 0, (PSIZE_T)&size); if (fSuccess) { // Set thread attribute list's Pseudo Console to the specified ConPTY fSuccess = UpdateProcThreadAttribute( lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, hPC, sizeof(HPCON), NULL, NULL); return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } // ... HANDLE hOut, hIn; HANDLE outPipeOurSide, inPipeOurSide; HANDLE outPipePseudoConsoleSide, inPipePseudoConsoleSide; HPCON hPC = 0; // Create the in/out pipes: CreatePipe(&inPipePseudoConsoleSide, &inPipeOurSide, NULL, 0); CreatePipe(&outPipeOurSide, &outPipePseudoConsoleSide, NULL, 0); // Create the Pseudo Console, using the pipes CreatePseudoConsole( {80, 32}, inPipePseudoConsoleSide, outPipePseudoConsoleSide, 0, &hPC); // Prepare the StartupInfoEx structure attached to the ConPTY. STARTUPINFOEX siEx{}; InitializeStartupInfoAttachedToConPTY(&siEx, hPC); // Create the client application, using startup info containing ConPTY info wchar_t* commandline = L"c:\\windows\\system32\\cmd.exe"; PROCESS_INFORMATION piClient{}; fSuccess = CreateProcessW( nullptr, commandline, nullptr, nullptr, TRUE, EXTENDED_STARTUPINFO_PRESENT, nullptr, nullptr, &siEx->StartupInfo, &piClient); // ... 

    cmd.exe ConPTY, CreatePseudoConsole() . ConPTY / Cmd. ResizePseudoConsole() , — ClosePseudoConsole() .


    ConPTY :

     // Input "echo Hello, World!", press enter to have cmd process the command, // input an up arrow (to get the previous command), and enter again to execute. std::string helloWorld = "echo Hello, World!\n\x1b[A\n"; DWORD dwWritten; WriteFile(hIn, helloWorld.c_str(), (DWORD)helloWorld.length(), &dwWritten, nullptr); 


    , ConPTY:

     // Suppose some other async callback triggered us to resize. // This call will update the Terminal with the size we received. HRESULT hr = ResizePseudoConsole(hPC, {120, 30}); 


    ConPTY:

     ClosePseudoConsole(hPC); 

    : ConPTY ConHost .

    !


    ConPTY API — , , Windows … !

    ConPTY API Microsoft, Microsoft ( Windows Linux (WSL), Windows Containers, VSCode, Visual Studio .), , @ConEmuMaximus5ConEmu Windows.

    , ConPTY API.


    , : ConHost . Console API. , , .

    , VT, , — .

    , Windows, /VT UTF-8 Console API: « VT» , Console API (, 16M RGB True Color ).

    /


    / , ConPTY API: , , , , .

    VSCode ( GitHub #45693 ) , Windows.

    ConPTY API


    ConPTY API Windows 10 / 2018 .

    Windows, , , ConPTY. Win32 API, API Runtime Dynamic Linking LoadLibrary() GetProcAddress() .

    Windows ConPTY, API ConPTY. , , .

    , ?


    … ! , , ! : D

    , , , . — , Windows , .

    . Windows Console GitHub . , .

Source: https://habr.com/ru/post/es420853/


All Articles