如何在没有延迟的情况下从Win32中的另一个进程捕获stdout?

mar*_*000 6 c++ winapi stdin stdout pipe

我想做的是类似于Visual Studio在其输出窗口或其工具窗口中的其他编辑器中执行的操作:从我的进程A启动另一个进程B并捕获其stdout/stderr输出.

到目前为止,我得到了它CreatePipe(),但由于某种原因,B的输出在写入时没有到达B. 它的行为更像某种缓冲区被填满,当它已满时,所有缓冲区内容立即到达A. 我编写了自己的测试程序,输出了一些内容并fflush(stdout)直接执行了.然后输出直接到达A.但我不能改变我想用这种方式使用的所有B进程的代码.试图从A冲洗管道也不起作用.

这应该怎么样?

我的初始化代码以及使用代码:

 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
 sa.bInheritHandle = TRUE;
 sa.lpSecurityDescriptor = NULL;

 err = CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, stdouthistory);
 if (err == 0)
     return 1;
 err = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
                       GetCurrentProcess(), &hChildStdoutRdDup , 0,
                       FALSE,
                       DUPLICATE_SAME_ACCESS);
 if (err == 0)
     return 3;
 CloseHandle(hChildStdoutRd);

 DWORD a, b, c;
 a = PIPE_READMODE_BYTE | PIPE_NOWAIT;
 b = 0;
 c = 0;
 SetNamedPipeHandleState(hChildStdoutRdDup, &a, &b, &c);

 err = CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, stdinhistory);
 if (err == 0)
     return 1;
 err = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
                       GetCurrentProcess(), &hChildStdinWrDup , 0,
                       FALSE,
                       DUPLICATE_SAME_ACCESS);
 if (err == 0)
     return 4;
 CloseHandle(hChildStdinWr);

 a = PIPE_READMODE_BYTE | PIPE_NOWAIT;
 b = 0;
 c = 0;

 ZeroMemory(&si,sizeof(STARTUPINFO));
 si.cb = sizeof(STARTUPINFO);
 si.dwFlags = STARTF_USESTDHANDLES;
 si.wShowWindow = SW_SHOW;

 si.hStdOutput = hChildStdoutWr;
 si.hStdError = hChildStdoutWr;
 si.hStdInput = hChildStdinRd;

 ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );

 err = CreateProcess(0, this->cmdline, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi);
 if (err == 0)
     return 4;
Run Code Online (Sandbox Code Playgroud)

消费:

 DWORD avail;
 unsigned int ofs = 0;
 if (PeekNamedPipe(hChildStdoutRdDup, NULL, 0, NULL, &avail, NULL))
 {
     if (avail != 0)
     {
         int err = ReadFile(hChildStdoutRdDup, s + ofs, slen, &threadbuffern, 0);
                           // Consume ...
     }
 }
Run Code Online (Sandbox Code Playgroud)

编辑:我刚刚发现了这个问题:在Ruby中连续读取外部进程的STDOUT.这是同样的问题,但在Ruby的上下文中.可悲的是,解决方案是使用一些让它工作的Ruby库.那个图书馆是怎么做到的?Win32/C++中的等价物是什么?

Bil*_*eal 4

你不能那样做。如果输出在有问题的进程中没有被刷新,那么它实际上并没有首先被写入标准输出。也就是说,操作系统实际上还没有从目标进程获取数据。

这不是管道的任何固有延迟,而是您正在监视的程序实际上尚未将其写入管道。

您应该注意到执行所述程序时命令提示符的行为完全相同,因为命令提示符使用与您正在使用的相同的管道解决方案。如果不这样做,那是因为相关程序检测到它们正在写入文件句柄,而不是控制台句柄,并进行额外的缓冲。