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

Fre*_*abe 5 c++ windows winapi pipe createprocess

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

我的第一次尝试是设置STARTUPINFO传递给CreateProcess喜欢的结构

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;
Run Code Online (Sandbox Code Playgroud)

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

基于创建具有重定向输入和输出的子进程示例的第二个想法是设置三个管道以转发写入任何管道的所有数据.由于我不知道如何等待数据写入多个文件(WaitForMultipleObjects无法在管道上同步),我考虑有三个线程,每个线程ReadFile在管道上进行阻塞调用.

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

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

Igo*_*nik 5

为了在多个文件或管道上等待 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);
Run Code Online (Sandbox Code Playgroud)

ReadFile并且WaitForMultipleObjects需要在循环中调用。您检查返回值WaitForMultipleObjects以了解哪个操作已完成,用于GetOverlappedResult发现该操作的结果(是否成功,如果成功,检索了多少字节),处理数据,ReadFile如果您想再次调用该句柄从中多读一些,然后继续等待。这有点类似于selectLinux 中由非阻塞 I/O 驱动的循环。

更高级的技术是I/O 完成端口。这允许一个线程池处理大量异步 I/O。常用于 Web 服务器等,可能对您的情况来说太过分了。


Fre*_*abe 1

如果您确保不在的参数中传递参数,则填充STARTUPINFOOP 所示的效果很好。CREATE_NO_WINDOWdwFlagsCreateProcess