2013-10-29 17 views
5

Sto utilizzando CreateProcess per avviare un interprete di script interattivo e vorrei inoltrare in modo trasparente stdin/stdout/stderr da/all'interprete.Come avviare correttamente un processo e inoltrare stdin/stdout/stderr?

Il mio primo tentativo è stato quello di impostare la struttura di STARTUPINFO passata al CreateProcess come

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; 

Vale a dire Ho provato a fare in modo che il processo dell'interprete di script usasse lo stesso handle per la lettura/scrittura come il mio processo di avvio utilizza. Questo non sembrava funzionare (non sono nemmeno sicuro che quelle maniglie standard possano essere ereditate).

Una seconda idea, basata sull'esempio Creating a Child Process with Redirected Input and Output, consiste nell'impostare tre pipe per inoltrare tutti i dati scritti su una qualsiasi delle pipe. Dato che non so come aspettare che i dati vengano scritti su più di un file (WaitForMultipleObjects non può essere sincronizzato su pipe), stavo considerando di avere tre thread, ognuno dei quali stava facendo una chiamata di blocco su ReadFile.

Ho il sospetto che questo potrebbe essere eccessivo, quindi mi chiedo: c'è un modo più semplice per farlo? Non ho bisogno di fare alcun tipo di elaborazione dei dati passati da/all'interprete di script a tutti.

Come nota a margine, su Linux sto usando execvp per sostituire solo il processo corrente con il processo dell'interprete di script, ma su Windows ho bisogno di avviare l'interprete di script con il thread principale in sospeso (in modo che io possa fare qualche patch bytecode) - quindi anche dal momento che _execvp sembra essere disponibile su Windows, apparentemente devo usare CreateProcess.

+2

possibile duplicato di [Creazione di CreateProcess ereditare la console del processo chiamante] (http://stackoverflow.com/questions/340356/making-createprocess-inherit-the-console-of-the-calling-process) –

+2

Re : come aspettare I/O su più di un file. Si crea una struttura 'OVERLAPPED', completa di un handle di evento, per ogni handle di file e si generano richieste di I/O asincrone (ad esempio' ReadFile') che passano le strutture 'OVERLAPPED' in. Quindi si attendono tali handle di evento. –

+0

Potresti approfondire questo argomento in una risposta, @Igor? Questa sembra essere la differenza principale da [precedente] (http://stackoverflow.com/questions/5485923/launch-an-exe-process-with-stdin-stdout-and-stderr) [domande] (http: // StackOverflow.it/questions/340356/making-createprocess-inherit-the-console-of-the-call-process) qui. – Shog9

risposta

1

Popuplating la STARTUPINFO come indicato dal PO funziona bene se hai la certezza di non passare l'argomento CREATE_NO_WINDOW nel dwFlags argomento CreateProcess.

4

Per attendere l'I/O su più file o pipe, si eseguono richieste I/O asincrone su ciascuno di questi file, quindi attendere il completamento di tali richieste. Qualcosa in questo senso (non testati):

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 e WaitForMultipleObjects avrebbe bisogno di essere chiamato in un ciclo. Si controlla il valore di ritorno di WaitForMultipleObjects per sapere quale operazione è stata completata, utilizzare GetOverlappedResult per scoprire l'esito di tale operazione (se è riuscita, e in tal caso, quanti byte ha recuperato), elaborare i dati, chiamare di nuovo ReadFile per tale handle se vuoi leggerne ancora un po ', poi tornare ad aspettare. Questo è in qualche modo simile a un ciclo di I/O non bloccante guidato da select in Linux.

La tecnica ancora più avanzata è I/O completion ports. Ciò consente di avere un pool di thread che gestisce molti I/O asincroni. Comunemente utilizzato nei server Web e simili, probabilmente eccessivo per il tuo caso.

+0

+1 sembra molto bello! –

Problemi correlati