如何从正在生成Windows进程的进程中捕获stdin/stderr?

nxagd54h  于 2022-11-18  发布在  Windows
关注(0)|答案(1)|浏览(162)

因此,我尝试从正在生成的进程中捕获stdoutstderr
1.我创建了一些FIFO:

HANDLE hstdout;
 while ((hstdout = CreateNamedPipe(
     stdout_filename.c_str()
     , PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE
     , PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS
     , 10
     , 4096
     , 4096
     , 0
     , &sa)) == INVALID_HANDLE_VALUE)
 {
     // In case the fifo is already in use, add a _ to the name and try again.
     stdout_filename += L"_";
 }

我对stderr做了同样的处理。
1.然后,我创建了一个过程,包括它所需要的一切:

PROCESS_INFORMATION pi = {};
 ZeroMemory(&pi, sizeof(pi));
 STARTUPINFO sui = {
     sizeof(STARTUPINFO)              // size
     , 0                              // reserved
     , nullptr                        // desktop
     , nullptr                        // title
     , 0, 0, 0, 0                     // x, y, cx, cy
     , 0, 0                           // x buffer, y buffer
     , 0                              // fill attribute
     , STARTF_FORCEOFFFEEDBACK        // flags
       | STARTF_USESTDHANDLES
     , false                          // show window
     , 0                              // reserved
     , 0                              // reserved
     , GetStdHandle(STD_INPUT_HANDLE) // stdin
     , hstdout                        // stdout
     , hstderr                        // stderr
 };

 BOOL success
     = CreateProcess(
         nullptr                      // application name
         , &cmdline[0]                // command line
         , nullptr                    // process attributes
         , nullptr                    // security attributes
         , true                       // inherit handles
         , CREATE_NO_WINDOW           // creation flags
           | INHERIT_PARENT_AFFINITY
         , nullptr                    // environment
         , nullptr                    // current directory
         , &sui                       // startup info
         , &pi                        // process info
     );

1.然后我侍候着把手:

if (success) {
     WCHAR buffer[4096];
     DWORD bytesRead;
     enum               { eStdOut, eStdErr, eProcess };
     HANDLE handles[] = { hstdout, hstderr, pi.hProcess };
     DWORD waitResult;
     bool process_terminated = false;
     do {
         waitResult = WaitForMultipleObjects(_countof(handles), handles, TRUE, INFINITE);
         switch (waitResult) {
         case WAIT_TIMEOUT:
             log_fs << L"Error: Wait timed out\n";
             break;

         case WAIT_FAILED:
             log_fs << L"Error: Wait failed\n";
             break;

         case eStdOut + WAIT_OBJECT_0:
             // stdin signaled
             if (ReadFile(hstdout, buffer, _countof(buffer), &bytesRead, nullptr)) {
                 log_fs.write(buffer, bytesRead);
                 wcout.write(buffer, bytesRead);
             }
             else {
                 log_fs << "Error reading from stdout" << endl << get_error() << endl;
             }
             break;

         case eStdErr + WAIT_OBJECT_0:
             // stderr signaled
             if (ReadFile(hstderr, buffer, _countof(buffer), &bytesRead, nullptr)) {
                 log_fs.write(buffer, bytesRead);
                 wcerr.write(buffer, bytesRead);
             }
             else {
                 log_fs << "Error reading from stderr" << endl << get_error() << endl;
             }
             break;

         case eProcess + WAIT_OBJECT_0:
             // process signaled it terminated
             log_fs << L"Process terminated" << endl;
             break;

         case eStdOut  + WAIT_ABANDONED_0:
         case eStdErr  + WAIT_ABANDONED_0:
         case eProcess + WAIT_ABANDONED_0:
             // One of the handles have been abandoned.
             log_fs << L"Error: wait abandoned " << (waitResult - WAIT_ABANDONED_0)
                 << endl << get_error() << endl;
             break;

         default:
             log_fs << L"Error: Unknown " << waitResult
                 << " (" << (waitResult - WAIT_OBJECT_0)
                 << ", " << (waitResult - WAIT_ABANDONED_0) << ")"
                 << endl << get_error() << endl;
             break;
         }
     } while (waitResult != WAIT_OBJECT_0 + eProcess);

     if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {
         log_fs << L"Error getting return code\n";
     }
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
 }

1.然后我用我的测试程序测试它:

int main()
 {
     std::cout << "Hello World!\n";
     std::cerr << "Hello Underworld!\n";
     // std::wstring str;
     // std::wcin >> str;
 }

eStdOut + WAIT_OBJECT_0的情况下,如果没有注解,它会执行到错误else,Windows错误字符串为“Waiting for a process to open the other end of the pipe”,然后无限期地阻塞在WaitForMultipleObjects上。
如果我取消注解测试文件中的最后两行,我的应用程序就会无限期地阻塞在WaitForMultipleObjects上。
我做错了什么?

olhwl3o2

olhwl3o21#

如果您查看MSDN上的Creating a Child Process with Redirected Input and Output示例,您将看到

  • 使用CreatePipe创建匿名管道。
  • 配置管道读写端的继承。
  • 在创建子进程之后,它们在读取/写入管道之前,会对不需要的管道末端进行CloseHandle操作!

关闭stdout的写入端的技巧意味着你可以从它读取直到管道中断。当发生这种情况时,你可以对进程WaitForSingleObject...

相关问题