2013-10-29 13 views
5

Ich benutze CreateProcess, um einen interaktiven Skript-Interpreter zu starten und möchte stdin/stdout/stderr vom/zum Interpreter transparent weiterleiten.Wie starte ich einen Prozess korrekt und übergebe stdin/stdout/stderr?

Mein erster Versuch zur Einrichtung war die STARTUPINFO Struktur wie

zu CreateProcess geben
STARTUPINFOA si = { sizeof(si) }; 
si.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); 
si.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); 
si.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); 
si.dwFlags |= STARTF_USESTDHANDLES; 

D.h. Ich habe versucht, den Skript-Interpreter-Prozess dazu zu bringen, den gleichen Handle zum Lesen/Schreiben zu verwenden, wie mein Launcher-Prozess verwendet. Das schien nicht zu funktionieren (ich bin mir nicht einmal sicher, ob diese Standard-Handles vererbt werden können).

Eine zweite Idee, die auf dem Creating a Child Process with Redirected Input and Output Beispiel basiert, besteht darin, drei Pipes einzurichten, um alle Daten, die an eine der Pipes geschrieben wurden, weiterzuleiten. Da ich nicht wissen kann, wie man darauf wartet, dass Daten in mehr als eine Datei geschrieben werden (WaitForMultipleObjects kann nicht auf Pipes synchronisiert werden), habe ich überlegt, drei Threads zu haben, von denen jeder einen blockierenden ReadFile Aufruf auf einer Pipe ausführt.

Ich vermute, dass dies vielleicht zu viel ist, aber ich frage mich: gibt es einen einfacheren Weg, dies zu tun? Ich muss keinerlei Verarbeitung der Daten durchführen, die von/an den Skript-Interpreter übertragen wurden.

Als Randnotiz benutze ich unter Linux execvp, um nur den aktuellen Prozess durch den Skript-Interpreter-Prozess zu ersetzen, aber unter Windows muss ich den Skript-Interpreter mit dem Haupt-Thread im suspendierten Zustand starten (damit ich es kann) mach ein Bytecode-Patching) - also, da _execvp unter Windows verfügbar zu sein scheint, muss ich CreateProcess verwenden.

+2

möglich Duplikat von [Making CreateProcess erbt die Konsole des aufrufenden Prozesses] (http://stackoverflow.com/questions/340356/making-createprocess-inherit-the-console-of-the-calling-process) –

+2

Re : Wie man auf I/O auf mehr als einer Datei wartet. Sie erstellen eine OVERLAPPED-Struktur mit einem Ereignishandle für jedes Dateihandle und geben asynchrone E/A-Anforderungen (z. B. ReadFile) aus, die diese OVERLAPPED-Strukturen übergeben. Warten Sie dann auf diese Ereignishandles. –

+0

Könnten Sie das in einer Antwort näher erläutern, @Igor? Das scheint der Hauptunterschied von [vorheriger] zu sein (http://stackoverflow.com/questions/5485923/launch-an-exe-process-with-stdin-stdout-and-stderr) [Fragen] (http: // Paketüberfluss.com/questions/340356/making-createprocess-erben-die-konsole-des-rufenden-prozesses) hier. – Shog9

Antwort

1

Popuplating die STARTUPINFO wie durch die OP gezeigt funktioniert gut wenn Sie sicherstellen, nicht das CREATE_NO_WINDOW Argument in dem von CreateProcessdwFlags Argumente übergeben.

4

Um auf I/O auf mehr als einer Datei oder einer Pipe zu warten, geben Sie asynchrone E/A-Anforderungen für jede dieser Dateien aus und warten auf den Abschluss der Anforderungen. Etwas in dieser Richtung (ungetestet):

HANDLE file1, file2; // initialized somehow 

HANDLE events[2]; 
events[0] = CreateEvent(NULL, TRUE, FALSE, NULL); 
events[1] = CreateEvent(NULL, TRUE, FALSE, NULL); 

OVERLAPPED overlapped1 = {0}; 
overlapped1.hEvent = events[0]; 
OVERLAPPED overlapped2 = {0}; 
overlapped2.hEvent = events[1]; 

ReadFile(file1, buffer1, size1, NULL, &overlapped1); 
ReadFile(file2, buffer2, size2, NULL, &overlapped2); 

WaitForMultipleObjects(2, events, FALSE, INFINITE); 

ReadFile und WaitForMultipleObjects müssten in einer Schleife aufgerufen werden. Sie überprüfen den Rückgabewert von WaitForMultipleObjects, um zu wissen, welche Operation abgeschlossen wurde, verwenden GetOverlappedResult, um das Ergebnis dieser Operation zu ermitteln (ob es erfolgreich war, und wenn ja, wie viele Bytes es abgerufen wurde), die Daten zu verarbeiten, ReadFile für dieses Handle erneut aufzurufen Sie möchten etwas mehr davon lesen und dann wieder warten. Dies ähnelt in gewisser Weise einer Schleife von nicht blockierenden E/A, die in Linux von select gesteuert wird.

Noch fortgeschrittenere Technik ist I/O completion ports. Dies ermöglicht es, einen Thread-Pool zu verwenden, der viele asynchrone E/A behandelt. Häufig in Web-Servern und so verwendet, wahrscheinlich zu viel für Ihren Fall.

+0

+1 das sieht sehr gut aus! –