如何正确启动进程并转发stdin / stdout / stderr?

时间:2013-10-29 13:12:10

标签: c++ windows winapi pipe createprocess

我正在使用CreateProcess启动交互式脚本解释器,并希望透明地将stdin / stdout / stderr转发给解释器。

我的第一次尝试是设置传递给STARTUPINFO的{​​{1}}结构,如

CreateProcess

即。我试图使脚本解释器进程使用与我的启动程序进程使用的读/写相同的句柄。这似乎不起作用(我甚至不确定那些标准句柄是否可以继承)。

基于Creating a Child Process with Redirected Input and Output示例的第二个想法是设置三个管道来转发写入任何管道的所有数据。由于我不知道如何等待数据写入多个文件(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; 无法在管道上同步),我正在考虑有三个线程,每个线程都进行阻塞WaitForMultipleObjects打电话给管道。

我怀疑这可能有点矫枉过正,所以我想知道:有更简单的方法吗?我根本不需要对从/向脚本解释器传递的数据进行任何处理。

作为旁注,在Linux上我使用ReadFile只是用脚本解释器进程替换当前进程,但在Windows上我需要启动脚本解释器,主线程处于挂起状态(所以我可以做一些字节码修补) - 所以即使因为_execvp似乎可以在Windows上使用,我显然必须使用CreateProcess。

2 个答案:

答案 0 :(得分:4)

为了在多个文件或管道上等待I / O,您对每个文件发出异步I / O请求,然后等待所述请求的完成。沿着这些方向的东西(未经测试):

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);
需要在循环中调用

ReadFileWaitForMultipleObjects。您检查WaitForMultipleObjects的返回值以了解哪个操作已完成,使用GetOverlappedResult来发现该操作的结果(是否成功,如果是,它检索了多少字节),处理数据如果你想从中再读一些,再次为该句柄调用ReadFile,然后再回到等待状态。这有点类似于Linux中由select驱动的非阻塞I / O循环。

更先进的技术是I/O completion ports。这允许一个线程池处理大量异步I / O.通常用于Web服务器等,可能对您的情况有些过分。

答案 1 :(得分:1)

如OP所示,填充STARTUPINFO可以正常,如果,请确保不会在CREATE_NO_WINDOW dwFlags参数中传递{{1}}参数}}