tags:

views:

36

answers:

2

Hi, I created two pipe to redirect child process stdin and stdout to parent process as given in http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx

The child process is an exe file. when executed using console it first returns a warning on STDOUT and then asks for a yes/no input from STDIN. when i am running the child process from my cpp program, the read pipe successfully reads the warning line from childs STDOUT but when try to send "yes" or "no" to child's STDIN using the write pipe the child program somehow does not receive it. however when i type it on the STDIN of parent the child process receives the yes and no .

Any idea why this is happening ?

A: 

Do you have sources of the child program? Check how it reads its input (or post the source here).

Does your child program work with cmd input redirection, e.g. if you do echo yes | childprogram.exe?

If not, chances are that the program uses low level console functions to do its input (maybe indirectly, e.g. via _getch()). In this case you may have to use WriteConsoleInput to simulate input.

Or, there may be a mistake in your redirection code. Post it here.

EDIT A sample of using 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;
}

The sample above has to be compiled as a console program, because it uses GetStdHandle to obtain console input handle. When parent is a console app, child console app will share the console with parent. If parent is a GUI app and thus has no console, use AttachConsole function to attach to the child process console before calling GetStdHandle, then call FreeConsole when finished with it.

atzz
it does not work with echo yes | . i tried that too .
gunjit mishra
@gunjit mishra -- then, the application either uses console I/O functions or reassigns its STDIO to console input stream. In both cases, `WriteConsoleInput` should help.
atzz
when i use writeconsoleinput on pipe handle it gives error "invalid access code". How can i create a pipe with generic read and write access.
gunjit mishra
@gunjit mishra -- you don't. Instead, write to the console directly. I've updated my answer with a sample.
atzz
that works .. thanks a lot !
gunjit mishra
A: 

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();



                  } 
gunjit mishra
sorry for the first two lines .. part of the code
gunjit mishra