【问题标题】:Not able to write on pipe Windows visual cpp无法在管道上写入 Windows Visual C++
【发布时间】:2010-06-29 08:39:26
【问题描述】:

我创建了两个管道来将子进程 stdin 和 stdout 重定向到父进程,如 http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx

子进程是一个exe文件。 当使用控制台执行时,它首先在 STDOUT 上返回一个警告,然后要求来自 STDIN 的是/否输入。 当我从我的 cpp 程序运行子进程时,读取管道成功地从子 STDOUT 读取警告行但是当尝试使用写入管道向子程序的 STDIN 发送“是”或“否”时,子程序以某种方式没有收到它.但是,当我在父进程的 STDIN 上键入它时,子进程会收到是和否。

知道为什么会这样吗?

【问题讨论】:

    标签: c++ windows pipe


    【解决方案1】:
    VOID WriteToPipe(VOID) 
    { 
     DWORD  dwWritten; 
      CHAR chBuf[3];
       sprintf(chBuf,"y\r\n");  
      if(logLevel==1) 
    log("trying to write y to child\n",1);
     // Read from a file and write its contents to a pipe. 
    
    
        if (! WriteFile(hChildStdinWr, chBuf, 3, 
          &dwWritten, NULL)) 
       if(logLevel ==1)
       log("cannot write to child in write\n",1);
    
     // Close the pipe handle so the child process stops reading. 
     /*
      if (! CloseHandle(hChildStdinWr)) {
       if(logLevel==1)     
         log("Close pipe failed in write \n");
       ExitProcess(0); 
       }
       */
     } 
    
    
    
     void ReadFromPipe(VOID) 
     { 
       DWORD dwRead, dwWritten; 
      CHAR chBuf[MAX]; 
    
      // Close the write end of the pipe before reading from the 
      // read end of the pipe. 
      log("reading data from child process \n",1 );
      /*if (!CloseHandle(hChildStdoutWr)) {
          cerr<<"Closing handle failed\n";
      ExitProcess(0); 
          }*/
    
         // Read output from the child process, and write to parent's STDOUT. 
    
        for(;;)
         { 
          if( !ReadFile( hChildStdoutRd, chBuf, MAX, &dwRead, 
            NULL) || dwRead == 0) break; 
            if (! WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL)) 
             break; 
    
            if(logLevel ==1) {
            log(chBuf,1);
              log("\n");
             }
            memset(chBuf,NULL,MAX);
           }
            log("finished reading \n",1);
             } 
    
    
    
           BOOL CreateChildProcess() 
            { 
              TCHAR szCmdline[1024] ;
              if(pool && !submit) {
              sprintf(szCmdline,"program.exe");
             }
             else {    
                 sprintf(szCmdline,"command.exe  argument");
                 }
    
                 PROCESS_INFORMATION piProcInfo; 
                 STARTUPINFO siStartInfo;
                 BOOL bFuncRetn = FALSE; 
    
               // Set up members of the PROCESS_INFORMATION structure. 
    
                     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
    
                // Set up members of the STARTUPINFO structure. 
    
                  ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
                siStartInfo.cb = sizeof(STARTUPINFO); 
                 siStartInfo.hStdError = hChildStdoutWr;
                siStartInfo.hStdOutput = hChildStdoutWr;
                siStartInfo.hStdInput = hChildStdinRd;
                 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
    
                   // Create the child process. 
    
                   bFuncRetn = CreateProcess(NULL, 
                 szCmdline,     // command line 
                  NULL,          // process security attributes 
                   NULL,          // primary thread security attributes 
                  TRUE,          // handles are inherited 
                  0,             // creation flags 
                  NULL,          // use parent's environment 
                   NULL,          // use parent's current directory 
                   &siStartInfo,  // STARTUPINFO pointer 
                  &piProcInfo);  // receives PROCESS_INFORMATION 
    
               if (bFuncRetn == 0)  {
                ExitProcess(0); 
               }
    
    
                  return bFuncRetn;
                   }
    
    
    
            void execute() {
    
           SECURITY_ATTRIBUTES saAttr; 
            BOOL fSuccess; 
           // Set the bInheritHandle flag so pipe handles are inherited. 
             saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
              saAttr.bInheritHandle = TRUE; 
              saAttr.lpSecurityDescriptor = NULL; 
           // Get the handle to the current STDOUT. 
             hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
           // Create a pipe for the child process's STDOUT. 
              if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
                ExitProcess(1);
                }
             // Ensure that the read handle to the child process's pipe for STDOUT is not  
                inherited.
           SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
                 // Create a pipe for the child process's STDIN. 
             if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
    
               ExitProcess(1);
                     }
            // Ensure that the write handle to the child process's pipe for STDIN is not 
                    nherited. 
                     SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0);
                 // Now create the child process. 
               fSuccess = CreateChildProcess(host,password,action,username);
              if (! fSuccess) {
            cerr<<"Create process failed";
                   ExitProcess(0); 
                   }
               CloseHandle(hChildStdinRd);
               CloseHandle(hChildStdoutWr);
    
    
    
                  WriteToPipe();
                    ReadFromPipe();
    
    
    
                      } 
    

    【讨论】:

      【解决方案2】:

      您有子程序的来源吗?检查它如何读取其输入(或在此处发布源代码)。

      您的子程序是否使用 cmd 输入重定向,例如如果你这样做echo yes | childprogram.exe

      如果不是,则程序可能使用低级别的console functions 进行输入(可能是间接的,例如通过_getch())。在这种情况下,您可能必须使用WriteConsoleInput 来模拟输入。

      或者,您的重定向代码可能有错误。在此处发布。

      编辑使用 WriteConsoleInput 的示例:

      #include <windows.h>
      #include <process.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      static const INPUT_RECORD SimulatedInput [] =
      {
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'e'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'c'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'h'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'o'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L' '}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'T'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'E'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'S'}, 0}},
          {KEY_EVENT, {TRUE, 1, 0, 0, {L'T'}, 0}},
          {KEY_EVENT, {TRUE, 1, VK_RETURN, 0, {L'\r'}, 0}},
      };
      
      int main( int, char*[] )
      {
          printf("\n(type 'exit' to exit the subshell)\n");
      
          // start a command interpreter asynchronously
          intptr_t process_handle = _spawnlp(_P_NOWAIT, "cmd", "/k", "prompt", "SUBSHELL: ", NULL);
      
          // get own console handle
          HANDLE con_input_handle = GetStdHandle(STD_INPUT_HANDLE);
      
          // send input to the console
          DWORD n_written;
          WriteConsoleInputW(con_input_handle, SimulatedInput, _countof(SimulatedInput), &n_written);
      
          // wait for child process to exit
          _cwait(NULL, process_handle, 0);
      
          return 0;
      }
      

      上面的示例必须编译为控制台程序,因为它使用GetStdHandle 来获取控制台输入句柄。当父级是控制台应用程序时,子级控制台应用程序将与父级共享控制台。如果 parent 是 GUI 应用程序因此没有控制台,请在调用 GetStdHandle 之前使用 AttachConsole 函数附加到子进程控制台,然后在完成后调用 FreeConsole

      【讨论】:

      • @gunjit mishra -- 然后,应用程序要么使用控制台 I/O 功能,要么将其 STDIO 重新分配给控制台输入流。在这两种情况下,WriteConsoleInput 都会有所帮助。
      • 当我在管道句柄上使用 writeconsoleinput 时,它会给出错误“无效的访问代码”。如何创建具有通用读写访问权限的管道。
      • @gunjit mishra——你不知道。相反,直接写入控制台。我已经用示例更新了我的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-28
      • 1970-01-01
      • 1970-01-01
      • 2015-01-07
      相关资源
      最近更新 更多