Artikel veröffentlicht am 2. August 2018Dies ist der zweite Artikel über die Windows-Befehlszeile, in dem wir die neuen Infrastruktur- und Programmierschnittstellen der Windows-Pseudokonsole, dh der Windows-Pseudokonsole (ConPTY), erläutern: Warum wir sie entwickelt haben, warum sie benötigt wird, wie sie funktioniert, wie sie verwendet wird und vieles mehr.
Im letzten Artikel
„Das schwere Erbe der Vergangenheit. Windows-Befehlszeilenprobleme “ Wir sprachen über die Voraussetzungen für die Entstehung des Terminals und die Entwicklung der Befehlszeile in Windows und begannen auch, die interne Struktur der Windows-Konsole und der Windows-Befehlszeileninfrastruktur zu untersuchen. Wir haben auch die vielen Vor- und Nachteile der Windows-Konsole erörtert.
Einer der Nachteile ist, dass Windows versucht, "nützlich" zu sein, aber Entwickler von alternativen Konsolen und Konsolen von Drittanbietern, Serviceentwickler usw. stört. Beim Erstellen einer Konsole oder eines Dienstes müssen Entwickler Zugriff auf Kommunikationskanäle haben, über die ihr Terminal / Dienst Daten mit Befehlszeilenanwendungen austauscht, oder Zugriff darauf gewähren. In der * NIX-Welt ist dies kein Problem, da * NIX eine Pseudo-Terminal-Infrastruktur (PTY) bereitstellt, mit der auf einfache Weise Kommunikationskanäle für eine Konsole oder einen Dienst erstellt werden können. Aber unter Windows war es nicht ...
… bis heute!Von TTY zu PTY
Bevor wir detailliert auf unsere Entwicklung eingehen, kehren wir kurz zur Entwicklung von Terminals zurück.
Am Anfang war TTY
Wie in einem
früheren Artikel erläutert, steuerten Benutzer in den frühen Tagen des Rechnens Computer mithilfe elektromechanischer Teletypen (TTYs), die über einen seriellen Kommunikationskanal (normalerweise über
eine 20-mA-Stromschleife ) mit einem Computer verbunden waren.
Ken Thompson und Dennis Ritchie (stehend) arbeiten am DEC PDP-11-Teletyp (Nachrichten ohne elektronische Anzeige)Terminalverteilung
Teletypen wurden durch Computerterminals mit elektronischen Anzeigen (normalerweise CRT-Bildschirme) ersetzt. In der Regel handelt es sich bei Terminals um sehr einfache Geräte (daher der Begriff "dummes Terminal"), die nur die Elektronik und die Verarbeitungsleistung enthalten, die für die folgenden Aufgaben benötigt werden:
- Empfang von Texteingaben über die Tastatur.
- Pufferung des eingegebenen Textes in einer Zeile (einschließlich lokaler Bearbeitung vor dem Senden).
- Senden / Empfangen von Text auf einem seriellen Kanal (normalerweise über die einst allgegenwärtige RS-232-Schnittstelle ).
- Anzeige des empfangenen Textes auf dem Terminal-Display.
Trotz ihrer Einfachheit (oder vielleicht auch dank dessen) wurden Terminals schnell zum Hauptmittel für die Verwaltung von Minicomputern, Mainframes und Servern: Die meisten Dateneingabebetreiber, Computerbetreiber, Systemadministratoren, Wissenschaftler, Forscher, Softwareentwickler und Branchengrößen arbeiteten an DEC-Terminals. IBM, Wyse und viele andere.
Admiral Grace Hopper in seinem Büro mit einem DEC VT220-Terminal auf seinem SchreibtischVerteilung von Software-Terminals
Seit Mitte der 1980er Jahre werden nach und nach Allzweckcomputer anstelle von Spezialterminals eingesetzt, die erschwinglicher, beliebter und leistungsfähiger geworden sind. Viele frühe PCs und andere Computer der 80er Jahre hatten Terminalanwendungen, die die RS-232-Verbindung zum PC öffneten und Daten mit anderen am anderen Ende der Verbindung austauschten.
Als Allzweckcomputer immer ausgefeilter wurden, erschienen eine grafische Benutzeroberfläche (GUI) und eine völlig neue Welt gleichzeitiger Anwendungen, einschließlich Terminalanwendungen.
Es gab jedoch ein Problem: Wie kann eine Terminalanwendung mit einer anderen Befehlszeilenanwendung interagieren, die auf demselben Computer ausgeführt wird? Und wie kann man ein serielles Kabel physisch zwischen zwei Anwendungen verbinden, die auf demselben Computer ausgeführt werden?
Pseudo-Terminal-Darstellung (PTY)
In der * NIX-Welt wurde das Problem durch die Einführung eines
Pseudo-Terminals (PTY) gelöst.
PTY emuliert serielle Telekommunikationsgeräte in einem Computer, indem Master- und Slave-Pseudogeräte („Master“ und „Slave“) verfügbar gemacht werden: Terminalanwendungen stellen eine Verbindung zum Master-Pseudogerät her, und Befehlszeilenanwendungen (z. B. Shells wie cmd, PowerShell und bash) stellen eine Verbindung zum Slave-Pseudogerät her. Wenn ein Terminal-Client Text- und / oder Steuerbefehle (als Text codiert) an das Master-Pseudogerät sendet, wird der Text in den ihm zugeordneten Slave übersetzt. Der Text aus der Anwendung wird an das Slave-Pseudogerät, dann zurück an den Master und damit an das Terminal gesendet. Daten werden immer asynchron gesendet / empfangen.
Pseudo-Terminal-Anwendung / ShellEs ist wichtig zu beachten, dass das Pseudo-Slave-Gerät das Verhalten des physischen Terminals emuliert und Befehlszeichen in POSIX-Signale konvertiert. Wenn der Benutzer beispielsweise
STRG + C in das Terminal eingibt, wird der ASCII-Wert für STRG + C (0x03) über den Master gesendet. Beim Empfang auf einem Slave-Pseudogerät wird der Wert 0x03 aus dem Eingangsstrom entfernt und ein
SIGINT-Signal erzeugt.
Eine solche PTY-Infrastruktur wird häufig von * NIX-Terminalanwendungen, Textfeldmanagern (z. B. Bildschirm, tmux) usw. verwendet. Diese Anwendungen rufen
openpty()
, das ein Paar Dateideskriptoren (fd) für den PTY-Master und
openpty()
zurückgibt. Dann kann die Anwendung eine untergeordnete Befehlszeilenanwendung (z. B. bash) verzweigen / ausführen, die ihre fd-Slaves verwendet, um Text abzuhören und an das verbundene Terminal zurückzugeben.
Dieser Mechanismus ermöglicht es Terminalanwendungen, direkt mit lokal ausgeführten Befehlszeilenanwendungen zu „kommunizieren“, so wie ein Terminal über eine serielle / Netzwerkverbindung mit einem Remotecomputer kommunizieren würde.
Was, kein Pseudokonsolen-Windows?
Wie bereits im vorherigen Artikel erläutert, ähnelt die Windows-Konsole zwar konzeptionell dem herkömmlichen * NIX-Terminal, unterscheidet sich jedoch in mehreren wesentlichen Punkten, insbesondere auf den untersten Ebenen, was für Entwickler von Windows-Befehlszeilenanwendungen, Terminals / Konsolen von Drittanbietern und Servern zu Problemen führen kann Anwendungen:
- Unter Windows gibt es keine PTY-Infrastruktur : Wenn ein Benutzer eine Befehlszeilenanwendung startet (z. B. Cmd, PowerShell, wsl, ipconfig usw.), verbindet Windows selbst eine neue oder vorhandene Instanz der Konsole mit der Anwendung.
- Windows stört Konsolen und Serveranwendungen von Drittanbietern : Windows bietet Terminals (derzeit) keine Möglichkeit, Kommunikationskanäle bereitzustellen, über die sie mit einer Befehlszeilenanwendung interagieren möchten. Terminals von Drittanbietern müssen Konsolen außerhalb des Bildschirms erstellen, vom Benutzer eingegebene Daten dorthin senden und die Ausgabe verschrotten, indem sie auf dem eigenen Display der Konsole von Drittanbietern neu gezeichnet werden!
- Nur Windows verfügt über die Konsolen-API : Windows-Befehlszeilenanwendungen basieren auf der Win32- Konsolen -API, wodurch die Code-Portabilität verringert wird, da alle anderen Plattformen Text / VT unterstützen, nicht die API.
- Nicht standardmäßiger Remotezugriff : Die Abhängigkeit von Befehlszeilenanwendungen von der Consol-API erschwert die Interaktions- und Remotezugriffsskripts erheblich.
Was zu tun ist?
Viele,
viele Entwickler forderten häufig einen PTY-ähnlichen Mechanismus unter Windows an, insbesondere diejenigen, die mit den Tools ConEmu / Cmder, Console2 / ConsoleZ, Hyper, VSCode, Visual Studio, WSL, Docker und OpenSSH arbeiten.
Sogar Peter Bright, der Technologie-Editor von Ars Technica, bat mich einige Tage später, den PTY-Mechanismus zu implementieren, als ich anfing, im Konsolenteam zu arbeiten:

Und vor kurzem wieder:

Nun, wir haben es endlich
geschafft :
Wir haben eine Pseudokonsole für Windows erstellt :
Willkommen in der Windows Pseudo Console (ConPTY)
Seit der Gründung des Konsolenteams vor etwa vier Jahren hat die Gruppe die Windows-Konsole und die internen Mechanismen der Befehlszeile überarbeitet. Gleichzeitig haben wir die oben beschriebenen Probleme und viele andere damit zusammenhängende Probleme regelmäßig und sorgfältig geprüft. Aber die Infrastruktur und der Code waren noch nicht bereit, die Veröffentlichung der Pseudokonsole zu ermöglichen ... bis jetzt!
Die neue Windows-Pseudokonsoleninfrastruktur (ConPTY), die API und einige andere damit verbundene Änderungen werden eine ganze
Reihe von Problemen beseitigen / lindern ...
ohne die Abwärtskompatibilität mit vorhandenen Befehlszeilenanwendungen zu beeinträchtigen !
Die neue Win32 ConPTY-API (offizielle Dokumentation wird in Kürze veröffentlicht) ist jetzt in den neuesten Insider-Builds von Windows 10 und dem entsprechenden Windows 10 Insider Preview SDK verfügbar. Sie werden in der nächsten Hauptversion von Windows 10 (irgendwann im Herbst / Winter 2018) erscheinen.
Konsolen- / ConHost-Architektur
Um ConPTY zu verstehen, müssen Sie die Architektur der Windows-Konsole studieren, oder besser ... ConHost!
Es ist wichtig zu verstehen, dass ConHost zwar alles implementiert, was Sie als Windows-Konsolenanwendung sehen und wissen, ConHost jedoch auch den größten Teil der Windows-Befehlszeileninfrastruktur enthält und implementiert! Von nun an wird
ConHost zu einem echten "Konsolenknoten" , der alle Befehlszeilenanwendungen und / oder GUI-Anwendungen unterstützt, die mit Befehlszeilenanwendungen interagieren!
Wie? Warum? Was? Schauen wir uns das genauer an.
Hier ist eine allgemeine Ansicht der internen Konsolenarchitektur / ConHost:

Im Vergleich zur Architektur aus dem
vorherigen Artikel enthält ConHost jetzt mehrere zusätzliche Module für die VT-Verarbeitung und das neue ConPTY-Modul, das offene APIs implementiert:
- ConPTY-API : Die neuen Win32-ConPTY-APIs bieten einen ähnlichen Mechanismus wie das POSIX PTY-Modell, jedoch unter Windows-Refraktion.
- VT-Interaktivität : Empfängt Eingabetext in UTF-8-Codierung, konvertiert jedes angezeigte Textzeichen in den entsprechenden
INPUT_RECORD
Datensatz und speichert ihn im Eingabepuffer. Es verarbeitet auch Escape-Sequenzen wie 0x03 (STRG + C) und konvertiert sie in KEY_EVENT_RECORDS
, die die entsprechende Escape-Aktion erzeugen. - VT-Renderer : Erzeugt VT-Sequenzen, die zum Bewegen des Cursors und zum Rendern von Text und Stil in Bereichen des Ausgabepuffers erforderlich sind, die sich gegenüber dem vorherigen Frame geändert haben.
OK, aber was bedeutet das wirklich?
Wie funktionieren Windows-Befehlszeilenanwendungen?
Um die Auswirkungen der neuen ConPTY-Infrastruktur besser zu verstehen, schauen wir uns an, wie Windows-Konsolen- und Befehlszeilenanwendungen bisher funktioniert haben.
Wenn ein Benutzer eine Befehlszeilenanwendung wie Cmd, PowerShell oder ssh startet, erstellt Windows einen neuen Win32-Prozess, in den die ausführbare Binärdatei der Anwendung und alle Abhängigkeiten (Ressourcen oder Bibliotheken) geladen werden.
Ein neu erstellter Prozess erbt normalerweise die Deskriptoren stdin und stdout von seinem übergeordneten Prozess. Wenn der übergeordnete Prozess ein Windows-GUI-Prozess war, fehlen die Deskriptoren stdin und stdout, sodass Windows die neue Anwendung bereitstellt und an die neue Konsoleninstanz anfügt. Die Kommunikation zwischen Befehlszeilenanwendungen und ihrer Konsole wird über ConDrv übertragen.
Wenn Sie beispielsweise von einer PowerShell-Instanz ohne erhöhte Berechtigungen ausgeführt werden, erbt der neue Anwendungsprozess die übergeordneten Deskriptoren stdin / stdout und empfängt daher Eingabedaten und gibt die Ausgabe an dieselbe Konsole wie die übergeordnete aus.
Hier müssen wir eine Reservierung vornehmen, da in einigen Fällen Befehlszeilenanwendungen gestartet werden, die an eine neue Instanz der Konsole angehängt sind, insbesondere aus Sicherheitsgründen, aber die obige Beschreibung ist normalerweise wahr.
Wenn die Befehlszeilen- / Shell-Anwendung gestartet wird, verbindet Windows sie letztendlich über ConDrv mit der Konsoleninstanz (ConHost.exe):

Wie funktioniert ConHost?
Immer wenn eine Befehlszeilenanwendung ausgeführt wird, verbindet Windows die Anwendung mit einer neuen oder vorhandenen Instanz von ConHost. Die Anwendung und ihre Konsoleninstanz sind über den Kernelmodus-Konsolentreiber (ConDrv) verbunden, der IOCTL-Nachrichten sendet / empfängt, die serialisierte API-Aufrufanforderungen und / oder Textdaten enthalten.
Historisch gesehen ist die Arbeit von ConHost, wie in einem früheren Artikel erwähnt, heute relativ einfach:
- Der Benutzer generiert Eingaben über Tastatur / Maus / Stift / Touchpad, die in
KEY_EVENT_RECORD
oder MOUSE_EVENT_RECORD
und im Eingabepuffer gespeichert werden. - Der Eingabepuffer wird jeweils für einen Datensatz geleert und führt die angeforderten Eingabeaktionen aus, z. B. Anzeigen von Text auf dem Bildschirm, Bewegen des Cursors, Kopieren / Einfügen von Text usw. Viele dieser Aktionen ändern den Inhalt des Ausgabepuffers. Diese geänderten Bereiche werden von der ConHost-Status-Engine aufgezeichnet.
- In jedem Frame zeigt die Konsole die geänderten Bereiche des Ausgabepuffers an.
Wenn die Befehlszeilenanwendung die Windows-Konsolen-API aufruft, werden die API-Aufrufe in IOCTL-Nachrichten serialisiert und über den ConDrv-Treiber gesendet. Anschließend werden IOCTL-Nachrichten an die angeschlossene Konsole gesendet, die den angeforderten API-Aufruf dekodiert und ausführt. Die zurückgegebenen / ausgegebenen Werte werden zurück in die IOCTL-Nachricht serialisiert und über ConDrv an die Anwendung zurückgesendet.
ConHost: Beitrag zur Vergangenheit für die Zukunft
Microsoft ist bestrebt, die Abwärtskompatibilität mit vorhandenen Anwendungen und Tools nach Möglichkeit aufrechtzuerhalten. Speziell für die Kommandozeile. Tatsächlich können 32-Bit-Versionen von Windows 10 immer noch viele / die meisten 16-Bit-Win16-Anwendungen und ausführbaren Dateien ausführen!
Wie oben erwähnt, besteht eine der Schlüsselrollen von ConHost darin, Dienste für seine Befehlszeilenanwendungen bereitzustellen, insbesondere für Legacy-Anwendungen, die die Win32-Konsolen-API aufrufen und sich darauf verlassen. Jetzt bietet ConHost neue Dienste an:
- Nahtlose PTY-ähnliche Infrastruktur für die Kommunikation mit modernen Konsolen und Terminals
- Aktualisieren älterer / traditioneller Befehlszeilenanwendungen
- Empfangen und Konvertieren von UTF-8-Text / VT in Eingabedatensätze (als ob vom Benutzer eingegeben)
- Die Konsolen-API ruft die gehostete Anwendung auf und aktualisiert ihren Ausgabepuffer entsprechend
- Zeigen Sie geänderte Bereiche des Ausgabepuffers in UTF-8-Codierung, Text / VT an
Das folgende Beispiel zeigt, wie eine moderne Konsolenanwendung über ConPTY ConHost mit einer Befehlszeilenanwendung kommuniziert.

In diesem neuen Modell:
- Konsole:
- Erstellt eigene Kommunikationskanäle
- Ruft die ConPTY-API auf, um ConPTY zu erstellen, und zwingt Windows, eine Instanz von ConHost auszuführen, die mit dem anderen Ende der Kanäle verbunden ist
- Erstellt wie gewohnt eine Instanz einer Befehlszeilenanwendung (z. B. PowerShell), die mit ConHost verbunden ist
- Conhost:
- Liest UTF-8-Text / VT am Eingang und konvertiert ihn in
INPUT_RECORD
Datensätze, die an die Befehlszeilenanwendung gesendet werden - Führen Sie API-Aufrufe von einer Befehlszeilenanwendung aus, die den Inhalt des Ausgabepuffers ändern kann
- Zeigt Änderungen im Ausgabepuffer in UTF-8-Codierung (Text / VT) an und sendet den empfangenen Text an die Konsole
- Befehlszeilenanwendung:
- Es funktioniert wie gewohnt, liest die Eingabe und ruft die Konsolen-API auf, ohne zu ahnen, dass sein ConPTY ConHost die Eingabe und Ausgabe von / nach UTF-8 übersetzt!
Der letzte Moment ist wichtig! Wenn die alte Befehlszeilenanwendung Aufrufe an die Konsolen-API wie
WriteConsoleOutput(...)
, wird der angegebene Text in den entsprechenden ConHost-Ausgabepuffer geschrieben. In regelmäßigen Abständen zeigt ConHost die geänderten Bereiche des Ausgabepuffers als Text / VT an, der über stdout an die Konsole zurückgesendet wird.
Letztendlich „sprechen“ sogar herkömmliche Befehlszeilenanwendungen von außen den Text / die VT
ohne Änderungen !
Mithilfe der neuen ConPTY-Infrastruktur können Konsolen von Drittanbietern jetzt direkt mit modernen und traditionellen Befehlszeilenanwendungen interagieren und alle in Text / VT austauschen.
Remote-Interaktion mit Windows-Befehlszeilenanwendungen
Der oben beschriebene Mechanismus funktioniert auf einem Computer einwandfrei, hilft aber auch bei der Interaktion, z. B. mit einer PowerShell-Instanz auf einem Windows-Remotecomputer oder in einem Container.
Beim Remote-Starten einer Befehlszeilenanwendung (d. H. Auf Remotecomputern, Servern oder Containern) tritt ein Problem auf. Tatsache ist, dass Befehlszeilenanwendungen auf Remotecomputern mit der lokalen ConHost-Instanz kommunizieren, da IOCTL-Nachrichten nicht für die Übertragung über das Netzwerk ausgelegt sind. Wie übertrage ich Eingaben von der lokalen Konsole auf den Remotecomputer und wie erhalte ich die Ausgabe von der dort ausgeführten Anwendung? Was tun mit Mac- und Linux-Computern, bei denen es Terminals, aber keine Windows-kompatiblen Konsolen gibt?
Um den Windows-Computer fernsteuern zu können, benötigen wir eine Art Kommunikationsbroker, der Daten über das Netzwerk transparent serialisieren, die Lebensdauer der Anwendungsinstanz verwalten usw. kann.
Vielleicht so etwas wie
ssh ?
Glücklicherweise wurde
OpenSSH kürzlich
auf Windows portiert und als
zusätzliche Option zu Windows 10 hinzugefügt. PowerShell Core verwendet ssh auch als eines der unterstützten
PowerShell Core Remoting-Remoting- Protokolle. Für Benutzer von Windows PowerShell ist das
Remoting von Windows PowerShell Remoting weiterhin eine akzeptable Option.
Lassen Sie uns sehen, wie Sie mit
OpenSSH für Windows jetzt Windows- Shells und Befehlszeilenanwendungen fernsteuern können:

OpenSSH enthält derzeit einige unerwünschte Komplikationen:
- Benutzer:
- Startet den SSH-Client und Windows verbindet die Konsoleninstanz wie gewohnt
- Gibt Text in die Konsole ein, der Tastenanschläge an den ssh-Client sendet
- SSH-Client:
- Liest die Eingabe als Bytes von Textdaten
- Sendet Textdaten über das Netzwerk an den sshd-Abhördienst
- Der sshd-Dienst durchläuft mehrere Phasen:
- Startet die Standard-Shell (z. B. Cmd), die Windows zwingt, eine neue Instanz der Konsole zu erstellen und zu verbinden
- Findet die Konsole der Cmd-Instanz und stellt eine Verbindung zu ihr her
- Verschiebt die Konsole vom Bildschirm (und / oder verbirgt sie)
- Sendet vom SSH-Client empfangene Eingaben als Eingabe an die Konsole außerhalb des Bildschirms
- Die cmd-Instanz funktioniert wie immer:
- Sammelt Eingaben vom sshd-Dienst
- Macht die Arbeit
- Ruft die Konsolen-API auf, um Text zu rendern / zu formatieren, den Cursor zu bewegen usw.
- Angehängte [Off-Screen] -Konsole:
- Führen Sie API-Aufrufe durch, indem Sie den Ausgabepuffer aktualisieren.
- Sshd-Dienst:
- Verschrottet den Ausgabepuffer der Off-Screen-Konsole, findet die Unterschiede, codiert sie in Text / VT und sendet ...
- Ein SSH-Client, der Text sendet ...
- Konsole, die Text anzeigt
Spaß, richtig? Überhaupt nicht! In dieser Situation kann vieles schief gehen, insbesondere beim Simulieren und Senden von Benutzereingaben und beim Leeren des Ausgabepuffers einer Off-Screen-Konsole. Dies führt zu Instabilität, Abstürzen, Datenkorruption, übermäßigem Energieverbrauch usw. Darüber hinaus entfernen nicht alle Anwendungen nicht nur den Text selbst, sondern auch seine Eigenschaften, weshalb Formatierung und Farbe verloren gehen!
Fernarbeit mit modernem ConHost und ConPTY
Sicher können wir die Situation verbessern? Ja, natürlich können wir - nehmen wir einige architektonische Änderungen vor und wenden unser neues ConPTY an:

Das Diagramm zeigt, dass sich die Schaltung wie folgt geändert hat:
- Benutzer:
- Startet den SSH-Client und Windows verbindet die Konsoleninstanz wie gewohnt
- Gibt Text in die Konsole ein, der Tastenanschläge an den ssh-Client sendet
- SSH-Client:
- Liest die Eingabe als Bytes von Textdaten
- Sendet Textdaten über das Netzwerk an den sshd-Abhördienst
- Sshd-Dienst:
- Erstellt stdin / stdout-Kanäle
- Ruft die ConPTY-API auf, um ConPTY zu initiieren
- Startet eine Cmd-Instanz, die mit dem anderen Ende von ConPTY verbunden ist. Windows initiiert und stellt eine neue Instanz von ConHost bereit
- Die cmd-Instanz funktioniert wie immer:
- Sammelt Eingaben vom sshd-Dienst
- Macht die Arbeit
- Ruft die Konsolen-API auf, um Text zu rendern / zu formatieren, den Cursor zu bewegen usw.
- Instanz ConPTY ConHost:
- Führen Sie API-Aufrufe durch, indem Sie den Ausgabepuffer aktualisieren.
- Zeigt die geänderten Bereiche des Ausgabepuffers als UTF-8-codierten Text / VT an, der über ssh an die Konsole / das Terminal zurückgesendet wird
Dieser Ansatz mit ConPTY ist für den sshd-Dienst eindeutig sauberer und einfacher. Die Aufrufe der Windows-Konsolen-API erfolgen vollständig in der ConHost-Instanz der Befehlszeilenanwendung, die alle sichtbaren Änderungen in Text / VT konvertiert. Wer sich mit ConHost verbindet, muss nicht wissen, dass die dortige Anwendung die Konsolen-API aufruft und keinen Text / VT generiert!
Stimmen Sie zu, dass dieser neue ConPTY-Remoting-Mechanismus zu einer eleganten, konsistenten und einfachen Architektur führt. In Kombination mit den leistungsstarken Funktionen von ConHost, der Unterstützung älterer Anwendungen und der Anzeige von Änderungen von Anwendungen, die die Konsolen-Konsolen-APIs als Text / VT aufrufen, hilft uns die neue ConHost- und ConPTY-Infrastruktur, die Vergangenheit in die Zukunft zu verschieben.
ConPTY API und wie man es benutzt
Die ConPTY-API ist in der aktuellen Version des Windows 10 Insider Preview SDK verfügbar.
Ich bin mir sicher, dass Sie es kaum erwarten können, Code zu sehen;)
Schauen Sie sich die API-Deklarationen an:
// 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);
Die obige API ConPTY stellt im Wesentlichen drei neue Funktionen zur Verfügung:
CreatePseudoConsole(size, hInput, hOutput, dwFlags, phPC)
- Erstellt pty mit einer Dimension in
w
Spalten und h
Zeilen unter Verwendung der vom Aufrufer erstellten Kanäle:
size
: Breite und Höhe (in Zeichen) des ConPTY-PuffershInput
: Zum Schreiben von Eingabedaten in PTY als Text- / VT-Sequenzen in UTF-8-CodierunghOutput
: Zum Lesen der Ausgabe von PTY als Text- / VT-Sequenzen in UTF-8-CodierungdwFlags
: Mögliche Werte:
PSEUDOCONSOLE_INHERIT_CURSOR
: Erstelltes ConPTY versucht, die Cursorposition der übergeordneten Terminalanwendung zu erben
phPC
: Konsolenhandle für von ConPty generiert
- Rückgabe : Erfolg / Misserfolg. Bei Erfolg enthält phPC das Handle für die neue ConPty
ResizePseudoConsole(hPC, size)
- Ändert die Größe des internen ConPTY-Puffers, um eine bestimmte Breite und Höhe anzuzeigen
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 . , .