Wenn du das selber machen willst, hast du aus Sicht der WinAPI zwei Möglichkeiten den Output von Konsolenapplikationen über den Parent-Prozess auszulesen:
- Per Anonymous Pipe
- Über den Console Screen Buffer
Beide Varianten haben Vor- und Nachteile, wobei Nr. 2 die eigentlich "sauberere" aber komplexere Variante ist.
Es gibt mittlerweile noch eine dritte Variante: "Pseudoconsole Sessions".
Das war zur damaligen Zeit, zu der ich mich mit diesem Thema befasst habe, aber noch nicht Spruchreif und ist zudem "nur" ab Windows 10 verfügbar.
(Beim Überfliegen liest sich das ähnlich zur Variante Nr. 2, nur hoffentlich mit weniger Bullshit...

)
Zu Nr. 1:
Grober Ablauf:
- Security-Attributes mit Vererbung definieren.
- Pipe-Handels per CreatePipe und den definierten Security-Attributes erzeugen.
- Startup-Info mit dem Write-Handle der Pipe als StdOutput und StdError definieren.
- Konsolenapplikationen über CreateProcess mit den definierten Security-Attributes und der Startup-Info ausführen.
- In einer Schleife auf den Child-Prozess mit geringem Timeout warten.
- Nach Ablauf des Timers oder nach Ende des Child-Prozesses die Pipe per ReadPipe mit dem Read-Handle auslesen.
Theoretisch ohne Threading machbar: Erstmal alle Prozesse starten und dann in einer Schleife die einzelnen Pipes auslesen.
Führt dann aber dazu, dass der Hauptprozess so lange beschäftigt ist, bis alle Child-Prozesse zum Ende gekommen sind.
Vorteile:
- Relativ simpel.
- Funktioniert auch mit crappy, schnell gehacktem Code.
- Kein Output geht verloren, da der Child-Prozess blockiert, wenn der Buffer von StdOuput oder StdError voll ist.
Nachteile:
- Der Child-Prozess blockiert, wenn der Buffer von StdOuput oder StdError voll ist.
- Auf Seiten des Hauptprozesses macht das vor allem bei viel schreibenden Anwendungen ein Auslesen und leeren des Pipe-Buffers in sehr kurzen Zeitabständen notwendig, um die Ausführung des Child-Prozess nicht unnötig aufzuhalten.
- Auf Seiten des Child-Prozesses kann es bei komplexen Anwendungen durch Blockierungen zu Fehlern kommen, wenn z.B. Timing-relevante oder/und Timeout-behaftete Dinge getan werden.
- Liefert nur den reinen Text des Outputs. Farbinformationen gehen verloren.
- Die Wahrscheinlichkeit, dass der Child-Prozess vom Windows-Scheduler auf seinem "eigenen" CPU-Core/Thread laufen gelassen werden kann, ist, wegen den häufigen Interaktion mit dem Hauptprozess, eher gering.
Zu Nr. 2:
Grober Ablauf:
- Security-Attributes mit Vererbung definieren.
- Les- und Schreibbaren Console Screen Buffer per CreateConsoleScreenBuffer und den definierten Security-Attributes erzeugen.
- Per GetConsoleScreenBufferInfo und SetConsoleScreenBufferInfo die Größe des Console Screen Buffers so groß wie möglich machen.
- Per FillConsoleOutputCharacter den Console Screen Buffer vorbelegen.
- Startup-Info mit dem Console-Screen-Buffer-Handle als StdOutput und StdError definieren.
- Konsolenapplikationen über CreateProcess mit den definierten Security-Attributes und der Startup-Info ausführen.
- Ab hier wirds jetzt u.U. kompliziert:
- Wenn man mit Sicherheit sagen kann, dass die Konsolenapplikationen nicht den kompletten Console Screen Buffer vollschreibt, ist es das Beste und einfachste, auf das Ende des Child-Prozesses zu warten, um dann per ReadConsoleOutput den Console Screen Buffer auszulesen.
- Steht es im Raum des Möglichen, dass die Konsolenapplikationen den kompletten Console Screen Buffer vollschreibt, wirds kompliziert (denn während dem Auslesen kann die Konsolenapplikationen ja weiterhin schreiben):
- Per GetConsoleScreenBufferInfo die Y-Position der Konsolenapplikationen beziehen. (Und hoffen, dass sie dem Ende noch nicht zu nah ist...)
- Per ReadConsoleOutput den Console Screen Buffer bis Y-1 auslesen.
- Per FillConsoleOutputCharacter bis Y-1 erneut vorbelegen (also quasi Leeren).
- Per SetConsoleScreenBufferInfo die Position der Konsolenapplikationen ganz auf Anfang setzen.
- Per ReadConsoleOutput den Console Screen Buffer ab Y bis Ende auslesen.
- Per FillConsoleOutputCharacter von Y bis Ende ebenso erneut vorbelegen (also quasi Leeren).
- Die beiden ausgelesenen Outputs so zusammenführen, wie sie zusammengehören.
- Rinse and Repeate bis der Child-Prozess zum Ende gekommen ist.
- Während des gesamten Vorgangs nicht vergessen immer schön zu Beten!
Theoretisch ohne Threading machbar, wenn davon ausgegangen werden kann, dass die Konsolenapplikationen nicht den gesamten Buffer mehr als vollschreiben: Erstmal alle Prozesse starten und dann in einer Schleife immer mal wieder die einzelnen Child-Prozesse abklappern, um zu schauen, ob sie schon fertig sind. Wenn ja, dann einfach Output auslesen.
Threading in wärmstens empfohlen, wenn möglichst garantiert werden soll, dass der gesamte Output einer jeder beliebigen Konsolenapplikationen erfasst wird, vor allem wenn diese viel schreiben und lange laufen.
Hintergrund ist der, dass der Konsolenapplikation ein alternativer Console Screen Buffer zur Verfügung gestellt wird, auf dem der Hauptprozess Lese- und Schreibrechte besitzt.
Dieser Console Screen Buffer funktioniert aber genauso, wie der Console Screen Buffer der Command Line. D.h. er kann maximal 32766 Zeilen lang sein und wird mehr hineingeschrieben, so läuft er über, indem die ersten Zeilen aus dem Buffer wieder entfernt werden.
Vorteile:
- Der Output kann 1-zu-1, also inkl. Farbinformationen, ausgelesen werden.
- Der Child-Prozess wird zu keiner Zeit blockiert.
- Wenn bis zum Ende des Child-Prozesses gewartet werden kann, ist die Wahrscheinlichkeit hoch, dass der Scheduler von Windows den Child-Prozess auf seinem "eigenen" CPU-Core/Thread laufen lassen wird.
Nachteile:
- Recht komplex in der Implementierung, es gibt viele kleine Fallstricke und viel zu beachten.
- Bei sehr schreiblustigen Anwendungen oder Verzögerungen im Hauptprozess keine 100%ige Garantie, dass lückenlos der komplette Output erfasst wird.
- Der Output ist entsprechend der 2-dimensionalen Ausmaße des Console Screen Buffers formatiert (genauso, wie man es aus der Command Line auch kennt). Das muss beachtet und behandelt werden, wenn der Inhalt wo anders sauber dargestellt werden soll.
- Es gibt Konsolenapplikationen (z.B. Ping), die "scheißen" auf den übergebenen Console Screen Buffer und schreiben stattdessen einfach in den Console Screen Buffer des Hauptprozesses durch.
(Kack Windows... mein Ernst! Was für eine Scheiße!!!
)