Article publié le 2 août 2018Il s'agit du deuxième article sur la ligne de commande Windows, où nous discuterons de la nouvelle infrastructure et des interfaces de programmation de la pseudo-console Windows, c'est-à-dire de la pseudo console Windows (ConPTY): pourquoi nous l'avons développée, pourquoi elle est nécessaire, comment elle fonctionne, comment l'utiliser et bien plus encore.
Dans le dernier article
«Le grave héritage du passé. Problèmes de ligne de commande Windows », nous avons parlé des conditions préalables à l'émergence du terminal et de l'évolution de la ligne de commande dans Windows, et avons également commencé à étudier la structure interne de la console Windows et l'infrastructure de ligne de commande Windows. Nous avons également discuté des nombreux avantages et inconvénients majeurs de la console Windows.
L'un des inconvénients est que Windows essaie d'être «utile», mais il interfère avec les développeurs de consoles alternatives et tierces, les développeurs de services, etc. Lors de la création d'une console ou d'un service, les développeurs doivent avoir accès aux canaux de communication par lesquels leur terminal / service échange des données avec des applications en ligne de commande, ou leur donner accès. Dans le monde * NIX, ce n'est pas un problème car * NIX fournit une infrastructure pseudo-terminal (PTY) qui facilite la création de canaux de communication pour une console ou un service. Mais sous Windows, ce n'était pas ...
... jusqu'à maintenant!Du TTY au PTY
Avant de parler en détail de notre développement, revenons brièvement au développement des terminaux.
Au début était ATS
Comme discuté dans un
article précédent , aux premiers jours de l'informatique, les utilisateurs contrôlaient les ordinateurs à l'aide de télétypes électromécaniques (TTY) connectés à un ordinateur via une sorte de canal de communication série (généralement via
une boucle de courant de 20 mA ).
Ken Thompson et Dennis Ritchie (debout) travaillent sur le télétype DEC PDP-11 (messages sans affichage électronique)Distribution des terminaux
Les télétypes ont été remplacés par des terminaux informatisés à affichage électronique (généralement des écrans CRT). En règle générale, les terminaux sont des dispositifs très simples (d'où le terme «terminal stupide»), contenant uniquement l'électronique et la puissance de traitement nécessaires pour les tâches suivantes:
- Réception de la saisie de texte depuis le clavier.
- Mise en mémoire tampon du texte saisi sur une seule ligne (y compris l'édition locale avant l'envoi).
- Envoi / réception de texte sur un canal série (généralement via l' interface RS-232 autrefois omniprésente).
- Affichage du texte reçu sur l'écran du terminal.
Malgré sa simplicité (ou peut-être grâce à elle), les terminaux sont rapidement devenus le principal moyen de gestion des mini-ordinateurs, des mainframes et des serveurs: la plupart des opérateurs de saisie de données, des opérateurs informatiques, des administrateurs système, des scientifiques, des chercheurs, des développeurs de logiciels et des sommités de l'industrie ont travaillé sur les terminaux DEC, IBM, Wyse et bien d'autres.
L'amiral Grace Hopper dans son bureau avec un terminal DEC VT220 sur son bureauDistribution de terminaux logiciels
Depuis le milieu des années 80, au lieu de terminaux spécialisés, des ordinateurs à usage général ont progressivement commencé à être utilisés, qui sont devenus plus abordables, populaires et puissants. De nombreux premiers PC et autres ordinateurs des années 80 avaient des applications de terminal qui ouvraient la connexion RS-232 au PC et échangeaient des données avec n'importe qui à l'autre extrémité de la connexion.
Au fur et à mesure que les ordinateurs à usage général devenaient plus sophistiqués, une interface utilisateur graphique (GUI) et un tout nouveau monde d'applications simultanées, y compris des applications de terminal, sont apparus.
Mais il y avait un problème: comment une application de terminal peut-elle interagir avec une autre application de ligne de commande s'exécutant sur la même machine? Et comment connecter physiquement un câble série entre deux applications s'exécutant sur le même ordinateur?
Apparence de pseudo-terminal (PTY)
Dans le monde * NIX, le problème a été résolu en introduisant un
pseudo-terminal (PTY) .
PTY émule un équipement de télécommunications série dans un ordinateur en exposant les pseudo-appareils maître et esclave («maître» et «esclave»): les applications de terminal se connectent au pseudo-appareil maître, et les applications de ligne de commande (par exemple, des shells comme cmd, PowerShell et bash) se connectent au pseudo-appareil esclave. Lorsqu'un client terminal transmet du texte et / ou des commandes de contrôle (codées sous forme de texte) au pseudo-périphérique maître, le texte est traduit vers l'esclave qui lui est associé. Le texte de l'application est envoyé au pseudo-périphérique esclave, puis renvoyé au maître et donc au terminal. Les données sont toujours envoyées / reçues de manière asynchrone.
Application / Shell pseudo-terminalIl est important de noter que le pseudo-périphérique «esclave» émule le comportement du terminal physique et convertit les caractères de commande en signaux POSIX. Par exemple, si l'utilisateur entre
CTRL + C dans le terminal, la valeur ASCII pour CTRL + C (0x03) est envoyée via le maître. Lorsqu'elle est reçue sur un pseudo-périphérique esclave, la valeur 0x03 est supprimée du flux d'entrée et un
signal SIGINT est généré.
Cette infrastructure PTY est largement utilisée par les applications de terminaux * NIX, les gestionnaires de panneaux de texte (par exemple, écran, tmux), etc. Ces applications appellent
openpty()
, qui renvoie une paire de descripteurs de fichiers (fd) pour le maître et l'esclave PTY. Ensuite, l'application peut créer / exécuter une application de ligne de commande enfant (par exemple, bash), qui utilise ses esclaves fd pour écouter et renvoyer du texte au terminal connecté.
Ce mécanisme permet aux applications du terminal de «parler» directement avec les applications de ligne de commande s'exécutant localement, tout comme un terminal parlerait à un ordinateur distant via une connexion série / réseau.
Quoi, pas de pseudo-console Windows?
Comme nous l'avons vu dans l'article précédent, bien que la console Windows soit conceptuellement similaire au terminal * NIX traditionnel, elle diffère de plusieurs manières clés, en particulier aux niveaux les plus bas, ce qui peut poser des problèmes aux développeurs d'applications de ligne de commande Windows, aux terminaux / consoles tiers et au serveur. applications:
- Windows n'a pas l'infrastructure PTY : lorsqu'un utilisateur lance une application en ligne de commande (par exemple, Cmd, PowerShell, wsl, ipconfig, etc.), Windows lui-même «connecte» une instance de console nouvelle ou existante à l'application.
- Windows interfère avec les consoles et les applications serveur tierces : Windows (actuellement) ne donne pas aux terminaux un moyen de fournir des canaux de communication par lesquels ils souhaitent interagir avec une application en ligne de commande. Les terminaux tiers doivent créer des consoles hors de l'écran, y envoyer des données saisies par l'utilisateur et supprimer la sortie en la redessinant sur le propre écran de la console tierce!
- Seul Windows possède l'API console : les applications de ligne de commande Windows s'appuient sur l'API Win32 Consol, ce qui réduit la portabilité du code, car toutes les autres plates-formes prennent en charge le texte / VT, pas l'API.
- Accès à distance non standard : la dépendance des applications de ligne de commande sur l'API Consol complique considérablement les scripts d'interaction et d'accès à distance.
Que faire
De
nombreux développeurs ont souvent demandé un mécanisme de type PTY sous Windows, en particulier ceux qui travaillent avec ConEmu / Cmder, Console2 / ConsoleZ, Hyper, VSCode, Visual Studio, WSL, Docker et OpenSSH.
Même Peter Bright, l'éditeur technologique d'Ars Technica, m'a demandé de mettre en œuvre le mécanisme PTY quelques jours plus tard lorsque j'ai commencé à travailler dans l'équipe de la console:

Et récemment encore:

Eh bien, nous l'avons finalement fait:
nous avons créé une pseudo-console pour Windows :
Bienvenue dans la pseudo console Windows (ConPTY)
Depuis la formation de la Console Team il y a environ quatre ans, le groupe s'est engagé dans la refonte de la console Windows et des mécanismes internes de la ligne de commande. Dans le même temps, nous avons régulièrement et soigneusement examiné les problèmes décrits ci-dessus et de nombreux autres problèmes et problèmes connexes. Mais l'infrastructure et le code n'étaient pas prêts à rendre possible la sortie de la pseudo-console ... jusqu'à maintenant!
La nouvelle infrastructure de pseudo-console Windows (ConPTY), l'API et certaines autres modifications connexes élimineront / atténueront toute une classe de problèmes ...
sans rompre la compatibilité descendante avec les applications de ligne de commande existantes !
La nouvelle API Win32 ConPTY (la documentation officielle sera publiée prochainement) est désormais disponible dans les dernières versions d'initiés de Windows 10 et le SDK Windows 10 Insider Preview correspondant . Ils apparaîtront dans la prochaine version majeure de Windows 10 (quelque part à l'automne / hiver 2018).
Architecture console / ConHost
Pour comprendre ConPTY, vous devez étudier l'architecture de la console Windows, ou plutôt ... ConHost!
Il est important de comprendre que bien que ConHost implémente tout ce que vous voyez et connaissez en tant qu'application de console Windows, ConHost contient et implémente également la plupart de l'infrastructure de ligne de commande Windows! Désormais,
ConHost devient un véritable "nœud de console" , prenant en charge toutes les applications de ligne de commande et / ou les applications GUI qui interagissent avec les applications de ligne de commande!
Comment? Pourquoi? Quoi? Examinons de plus près.
Voici une vue d'ensemble de l'architecture de la console interne / ConHost:

Par rapport à l'architecture de l'
article précédent , ConHost contient maintenant plusieurs modules supplémentaires pour le traitement VT et le nouveau module ConPTY qui implémente les API ouvertes:
- API ConPTY : Les nouvelles API Win32 ConPTY fournissent un mécanisme similaire au modèle POSIX PTY, mais en réfraction Windows.
- Interactivité VT : reçoit le texte d'entrée au codage UTF-8, convertit chaque caractère de texte affiché dans l'enregistrement
INPUT_RECORD
correspondant et l'enregistre dans le tampon d'entrée. Il traite également les séquences d'échappement, telles que 0x03 (CTRL + C), les convertissant en KEY_EVENT_RECORDS
, qui produisent l'action d'échappement appropriée. - VT Renderer : génère les séquences VT nécessaires pour déplacer le curseur et rendre le texte et le style dans les zones du tampon de sortie qui ont changé par rapport à l'image précédente.
OK, mais qu'est-ce que cela signifie vraiment?
Comment fonctionnent les applications de ligne de commande Windows?
Pour mieux comprendre l'impact de la nouvelle infrastructure ConPTY, regardons comment la console Windows et les applications en ligne de commande ont jusqu'à présent fonctionné.
Chaque fois qu'un utilisateur lance une application en ligne de commande telle que Cmd, PowerShell ou ssh, Windows crée un nouveau processus Win32 dans lequel il charge le binaire exécutable de l'application et toutes les dépendances (ressources ou bibliothèques).
Un processus nouvellement créé hérite généralement des descripteurs stdin et stdout de son parent. Si le processus parent était un processus d'interface graphique Windows, les descripteurs stdin et stdout sont manquants, donc Windows déploiera et attachera la nouvelle application à la nouvelle instance de console. La communication entre les applications de ligne de commande et leur console est transmise via ConDrv.
Par exemple, lors du démarrage à partir d'une instance PowerShell sans privilèges élevés, le nouveau processus d'application héritera des descripteurs parent stdin / stdout et, par conséquent, recevra les données d'entrée et sortira la sortie sur la même console que le parent.
Ici, nous devons faire une réservation, car dans certains cas, des applications de ligne de commande sont lancées attachées à une nouvelle instance de la console, en particulier pour des raisons de sécurité, mais la description ci-dessus est généralement vraie.
En fin de compte, lorsque l'application de ligne de commande / shell démarre, Windows la connecte à l'instance de console (ConHost.exe) via ConDrv:

Comment fonctionne ConHost?
Chaque fois qu'une application de ligne de commande est en cours d'exécution, Windows connecte l'application à une instance nouvelle ou existante de ConHost. L'application et son instance de console sont connectées via le pilote de console en mode noyau (ConDrv), qui envoie / reçoit des messages IOCTL contenant des demandes d'appel API sérialisées et / ou des données texte.
Historiquement, comme indiqué dans un article précédent, le travail de ConHost est relativement simple aujourd'hui:
- L'utilisateur génère une entrée à partir du clavier / souris / stylo / pavé tactile, qui est converti en
KEY_EVENT_RECORD
ou MOUSE_EVENT_RECORD
et stocké dans le tampon d'entrée. - Le tampon d'entrée est vidé un enregistrement à la fois, effectuant les actions d'entrée demandées, telles que l'affichage du texte à l'écran, le déplacement du curseur, le copier / coller du texte, etc. Beaucoup de ces actions modifient le contenu du tampon de sortie. Ces zones modifiées sont enregistrées par le moteur d'état ConHost.
- Dans chaque cadre, la console affiche les zones modifiées du tampon de sortie.
Lorsque l'application de ligne de commande appelle l'API de la console Windows, les appels d'API sont sérialisés en messages IOCTL et envoyés via le pilote ConDrv. Il délivre ensuite des messages IOCTL à la console connectée, qui décode et exécute l'appel d'API demandé. Les valeurs renvoyées / sorties sont sérialisées vers le message IOCTL et renvoyées à l'application via ConDrv.
ConHost: Contribuer au passé pour l'avenir
Microsoft s'efforce de maintenir la compatibilité descendante avec les applications et outils existants dans la mesure du possible. Surtout pour la ligne de commande. En fait, les versions 32 bits de Windows 10 peuvent toujours exécuter la plupart / la plupart des applications et exécutables Win16 16 bits!
Comme mentionné ci-dessus, l'un des rôles clés de ConHost est de fournir des services à ses applications de ligne de commande, en particulier les applications héritées qui appellent et s'appuient sur l'API de la console Win32. Désormais, ConHost propose de nouveaux services:
- Infrastructure transparente de type PTY pour la communication avec les consoles et terminaux modernes
- Mise à niveau d'applications héritées / traditionnelles en ligne de commande
- Réception et conversion de texte / VT UTF-8 en enregistrements d'entrée (comme s'ils étaient entrés par l'utilisateur)
- API de console appelle l'application hébergée, mettant à jour son tampon de sortie en conséquence
- Afficher les zones modifiées du tampon de sortie en encodage UTF-8, texte / VT
Voici un exemple de la façon dont une application de console moderne communique avec une application de ligne de commande via ConPTY ConHost.

Dans ce nouveau modèle:
- Console:
- Crée ses propres canaux de communication
- Appelle l'API ConPTY pour créer ConPTY, forçant Windows à exécuter une instance de ConHost connectée à l'autre extrémité des canaux
- Crée une instance d'une application de ligne de commande (par exemple PowerShell) connectée à ConHost, comme d'habitude
- Conhost:
- Lit le texte / VT UTF-8 à l'entrée et le convertit en enregistrements
INPUT_RECORD
, qui sont envoyés à l'application de ligne de commande - Effectuer des appels d'API à partir d'une application de ligne de commande qui peut modifier le contenu du tampon de sortie
- Affiche les modifications du tampon de sortie dans l'encodage UTF-8 (texte / VT) et envoie le texte reçu à sa console
- Application en ligne de commande:
- Il fonctionne comme d'habitude, lit l'entrée et appelle l'API de la console, n'ayant aucune idée que son ConPTY ConHost traduit l'entrée et la sortie de / vers UTF-8!
Le dernier moment est important! Lorsque l'ancienne application de ligne de commande utilise des appels à l'API de console comme
WriteConsoleOutput(...)
, le texte spécifié est écrit dans le tampon de sortie ConHost correspondant. Périodiquement, ConHost affiche les zones modifiées du tampon de sortie sous forme de texte / VT, qui est renvoyé via stdout à la console.
En fin de compte, même les applications de ligne de commande traditionnelles de l'extérieur "parlent" le texte / TV
sans aucun changement !
Grâce à la nouvelle infrastructure ConPTY, les consoles tierces peuvent désormais interagir directement avec les applications de ligne de commande modernes et traditionnelles et les échanger toutes en texte / TV.
Interaction à distance avec les applications de ligne de commande Windows
Le mécanisme décrit ci-dessus fonctionne correctement sur un ordinateur, mais aide également lors de l'interaction, par exemple, avec une instance PowerShell sur un ordinateur Windows distant ou dans un conteneur.
Il y a un problème lors du démarrage d'une application de ligne de commande à distance (c'est-à-dire sur des ordinateurs distants, des serveurs ou des conteneurs). Le fait est que les applications de ligne de commande sur les machines distantes communiquent avec l'instance ConHost locale, car les messages IOCTL ne sont pas conçus pour être transmis sur le réseau. Comment transférer les entrées de la console locale vers la machine distante et comment obtenir les sorties de l'application qui s'y exécute? De plus, que faire des machines Mac et Linux, où il y a des terminaux mais pas de consoles compatibles Windows?
Ainsi, afin de contrôler à distance la machine Windows, nous avons besoin d'une sorte de courtier en communication qui peut sérialiser les données en toute transparence sur le réseau, gérer la durée de vie de l'instance d'application, etc.
Peut-être quelque chose comme
ssh ?
Heureusement,
OpenSSH a été récemment
porté sur Windows et ajouté comme
option supplémentaire à Windows 10 . PowerShell Core utilise également ssh comme l'un des protocoles de
communication à distance PowerShell Core pris en charge. Et pour ceux qui exécutent Windows PowerShell, la
communication à distance de Windows PowerShell est toujours une option acceptable.
Voyons comment
OpenSSH pour Windows vous permet
désormais de contrôler à distance les shells
Windows et les applications en ligne de commande:

OpenSSH comprend actuellement certaines complications indésirables:
- Utilisateur:
- Démarre le client ssh et Windows connecte l'instance de console comme d'habitude
- Entre du texte dans la console, qui envoie des frappes au client ssh
- client ssh:
- Lit l'entrée sous forme d'octets de données texte
- Envoie des données texte sur le réseau au service d'écoute sshd
- Le service sshd passe par plusieurs étapes:
- Lance le shell par défaut (par exemple, Cmd), ce qui oblige Windows à créer et à connecter une nouvelle instance de la console
- Recherche et se connecte à la console de l'instance Cmd
- Déplace la console hors écran (et / ou la cache)
- Envoie l'entrée reçue du client ssh à la console hors écran comme entrée
- L'instance cmd fonctionne comme toujours:
- Collecte les entrées du service sshd
- Est-ce que le travail
- Appelle l'API de la console pour rendre / styliser le texte, déplacer le curseur, etc.
- Console [hors écran] attachée:
- Effectuez des appels d'API en mettant à jour le tampon de sortie.
- Service Sshd:
- Scraps le tampon de sortie de la console hors écran, trouve les différences, les encode en texte / VT et renvoie ...
- Un client ssh qui envoie du texte ...
- Console qui affiche du texte
Amusant, non? Pas du tout! Dans cette situation, beaucoup de choses peuvent mal tourner, en particulier dans le processus de simulation et d'envoi des entrées utilisateur et de vidage du tampon de sortie d'une console hors écran. Cela entraîne une instabilité, des plantages, une corruption des données, une consommation d'énergie excessive, etc. De plus, toutes les applications ne suppriment pas seulement le texte lui-même, mais aussi ses propriétés, c'est pourquoi la mise en forme et la couleur sont perdues!
Travail à distance avec ConHost et ConPTY modernes
Certes, nous pouvons améliorer la situation? Oui, bien sûr, nous pouvons - apportons quelques modifications architecturales et appliquons notre nouveau ConPTY:

Le diagramme montre que le circuit a changé comme suit:
- Utilisateur:
- Démarre le client ssh et Windows connecte l'instance de console comme d'habitude
- Entre du texte dans la console, qui envoie des frappes au client ssh
- client ssh:
- Lit l'entrée sous forme d'octets de données texte
- Envoie des données texte sur le réseau au service d'écoute sshd
- Service Sshd:
- Crée des canaux stdin / stdout
- Appelle l'API ConPTY pour lancer ConPTY
- Démarre une instance Cmd connectée à l'autre extrémité de ConPTY. Windows lance et monte une nouvelle instance de ConHost
- L'instance cmd fonctionne comme toujours:
- Collecte les entrées du service sshd
- Est-ce que le travail
- Appelle l'API de la console pour rendre / styliser le texte, déplacer le curseur, etc.
- Instance ConPTY ConHost:
- Effectuez des appels d'API en mettant à jour le tampon de sortie.
- Affiche les régions modifiées du tampon de sortie sous forme de texte / VT encodé UTF-8, qui est renvoyé à la console / au terminal via ssh
Cette approche utilisant ConPTY est clairement plus propre et plus simple pour le service sshd. Les appels à l'API de la console Windows sont entièrement effectués dans l'instance ConHost de l'application de ligne de commande, qui convertit toutes les modifications visibles en texte / VT. Celui qui se connecte à ConHost, il n'a pas besoin de savoir que l'application y appelle l'API Console, et ne génère pas de texte / VT!
Convenez que ce nouveau mécanisme d'accès distant ConPTY conduit à une architecture élégante, cohérente et simple. Combinées aux puissantes fonctionnalités intégrées à ConHost, à la prise en charge des anciennes applications et à l'affichage des modifications des applications qui appellent les API de la console de la console sous forme de texte / VT, la nouvelle infrastructure ConHost et ConPTY nous aide à déplacer le passé dans le futur.
API ConPTY et comment l'utiliser
L'API ConPTY est disponible dans la version actuelle du SDK Windows 10 Insider Preview .
Maintenant, je suis sûr que vous ne pouvez pas attendre de voir du code;)
Jetez un œil aux déclarations de l'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);
L'API ConPTY ci-dessus expose essentiellement trois nouvelles fonctions à utiliser:
CreatePseudoConsole(size, hInput, hOutput, dwFlags, phPC)
- Crée pty avec dimension dans les colonnes
w
et les lignes h
, en utilisant les canaux créés par l'appelant:
size
: largeur et hauteur (en caractères) du tampon ConPTYhInput
: pour écrire des données d'entrée dans PTY sous forme de séquences texte / VT dans le codage UTF-8hOutput
: pour lire la sortie de PTY sous forme de séquences texte / VT dans le codage UTF-8dwFlags
: Valeurs possibles:
PSEUDOCONSOLE_INHERIT_CURSOR
: PSEUDOCONSOLE_INHERIT_CURSOR
créé tentera d'hériter de la position du curseur de l'application de terminal parent
phPC
: handle de console pour généré par ConPty
- Retours : succès / échec. En cas de succès, phPC contient le handle du nouveau ConPty
ResizePseudoConsole(hPC, size)
- Redimensionne le tampon ConPTY interne pour afficher une largeur et une hauteur spécifiques
ClosePseudoConsole (hPC)
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 .), , @ConEmuMaximus5 — ConEmu 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 . , .