Не умеет писать на конвейере Windows visual cpp - PullRequest
0 голосов
/ 29 июня 2010

Я создал два канала для перенаправления дочернего процесса stdin и stdout в родительский процесс, как указано в http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx

Дочерний процесс - это исполняемый файл.при выполнении с помощью консоли сначала возвращает предупреждение о STDOUT, а затем запрашивает ввод да / нет из STDIN.когда я запускаю дочерний процесс из моей программы cpp, канал чтения успешно читает строку предупреждения из дочернего STDOUT, но при попытке отправить «да» или «нет» в дочерний STDIN с помощью канала записи дочерняя программа как-то не получает его,однако, когда я набираю его на STDIN родительского процесса, дочерний процесс получает да и нет.

Есть идеи, почему это происходит?

Ответы [ 2 ]

0 голосов
/ 29 июня 2010
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();



                  } 
0 голосов
/ 29 июня 2010

Есть ли у вас источники детской программы? Проверьте, как он читает свои входные данные (или опубликуйте источник здесь).

Работает ли ваша детская программа с перенаправлением ввода cmd, например, если вы делаете echo yes | childprogram.exe?

Если нет, есть вероятность, что программа использует низкоуровневые функции консоли для ввода (возможно, косвенно, например, через _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 является консольным приложением, дочернее консольное приложение будет использовать консоль совместно с parent. Если parent является приложением с графическим интерфейсом и, следовательно, не имеет консоли, используйте функцию AttachConsole для подключения к дочерней консоли процесса перед вызовом GetStdHandle, а затем вызовите FreeConsole , когда закончите с ним.

...