سؤال

I'm using CreateProcess to launch an interactive script interpreter and would like to transparently forward stdin/stdout/stderr from/to the interpreter.

My first attempt was to setup the STARTUPINFO structure passed to CreateProcess like

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;

I.e. I tried to make the script interpreter process use the very same handle for reading/writing as my launcher process uses. That didn't seem to work though (I'm not even sure those standard handles can be inherited).

A second idea, based on the Creating a Child Process with Redirected Input and Output example is to setup three pipes to forward all data written to any of the pipes. Since I don't know how to wait for data to be written to more than one file (WaitForMultipleObjects cannot synchronize on pipes), I was considering to have three threads, each of which doing a blocking ReadFile call on a pipe.

I suspect that this might be overkill though so I'm wondering: is there some easier way to do this? I don't need to do any kind of processing of the data passed from/to the script interpreter at all.

As a side note, on Linux I'm using execvp to just replace the current process with the script interpreter process, but on Windows I need to launch the script interpreter with the main thread in suspended state (so that I can do some bytecode patching) - so even since _execvp seems to be availble on Windows, I apparantly have to use CreateProcess.

هل كانت مفيدة؟

المحلول 2

Popuplating the STARTUPINFO as shown by the OP works fine if you make sure to not pass the CREATE_NO_WINDOW argument in the dwFlags argument of CreateProcess.

نصائح أخرى

In order to wait for I/O on more than one file or pipe, you issue asynchronous I/O requests on each of those files, then wait for completion of said requests. Something along these lines (untested):

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 and WaitForMultipleObjects would need to be called in a loop. You check the return value of WaitForMultipleObjects to know which operation has completed, use GetOverlappedResult to discover the outcome of that operation (whether it succeeded, and if so, how many bytes it retrieved), process the data, call ReadFile for that handle again if you want to read some more from it, then get back to waiting. This is somewhat similar to a loop of non-blocking I/O driven by select in Linux.

Still more advanced technique is I/O completion ports. This allows one to have a thread pool handling lots of asynchronous I/O. Commonly used in Web servers and such, probably overkill for your case.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top