?
Solved

Reading from a pipe

Posted on 1998-10-07
4
Medium Priority
?
1,923 Views
Last Modified: 2013-12-03
I'm writing a program where I kick off an executable and I want to read information that the program writes to stdout. I did a console app test program using _popen and it worked fine. However, when I dropped the code into the full gui the behaviour changed. It stopped reading from the stream returned from _popen (ie the spawned process would run to completeion before I could step to the read.) So I decided to try using CreatePipe and CreateProcess. (see below) What I'm having the real problem with is reading from the stdout of the created process.

The spawned process takes a while to run and writes update information to stdout. But what happens is that my program seems to wait at the ReadFile call until the process completes. By the time I return from ReadFile the pipe has been closed. Here's a sample of my code. (I'm fuzzy on the overlap structures usage. ) {MSDEV C++ 5.0 on Windows NT SVC pack 3}


  HANDLE hWrite, hRead, hError;
  HANDLE hHeap;
  OVERLAPPED PipeOverlapInfo = {0,0,0,0,0};
  SECURITY_ATTRIBUTES sa;

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

  if (!CreatePipe(&hRead, &hWrite, &sa, 4096)) {
    printf("error \n");
    exit(1);
  }
  STARTUPINFO StartupInfo;
  PROCESS_INFORMATION ProcessInformation;

  StartupInfo.cb = sizeof(STARTUPINFO);
  StartupInfo.lpReserved = NULL;
  StartupInfo.lpDesktop = NULL;
  StartupInfo.lpTitle = NULL;
  StartupInfo.dwX = 0L;
  StartupInfo.dwY = 0L;
  StartupInfo.dwXSize = 0L;
  StartupInfo.dwYSize = 0L;
  StartupInfo.dwXCountChars = 0L;
  StartupInfo.dwYCountChars = 0L;
  StartupInfo.dwFillAttribute = NULL;
  StartupInfo.dwFlags = STARTF_USESTDHANDLES;
  StartupInfo.wShowWindow = SW_SHOWDEFAULT;
  StartupInfo.cbReserved2 = 0;
  StartupInfo.lpReserved2 = NULL;
  StartupInfo.hStdOutput = hWrite;

  if (!DuplicateHandle(GetCurrentProcess(), hWrite, GetCurrentProcess(),
                       &hError, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
    printf ("error\n");
    exit(1);
  }
  StartupInfo.hStdError = hError;

  PipeOverlapInfo.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  if (PipeOverlapInfo.hEvent == NULL) {
    printf ("error\n");
    exit(1);
  }

  if (!CreateProcess(NULL, "C:\\WINNT\\system32\\more.com < swQueryLog.txt",
                     NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL,
                     &StartupInfo, &ProcessInformation)) {
    printf ("error\n");
    exit(1);
  }
 
  CloseHandle(hWrite);
  CloseHandle(hError);
  LPSTR lpoutput;

  DWORD availableOutput = 4096;
  BOOL TimeoutNotReached = TRUE;
  DWORD bytesRead;
  while (TimeoutNotReached) {
    if (ReadFile(hRead, psBuffer, availableOutput, &bytesRead,
                 &PipeOverlapInfo) == TRUE) {
      printf("we read");
    } else {
      int erco = GetLastError();
      switch (erco) {
      case ERROR_IO_PENDING:
        ResetEvent(PipeOverlapInfo.hEvent);
        break;
      case ERROR_MORE_DATA:
        printf("Buffer is too small");
        break;
      case ERROR_BROKEN_PIPE:
        // We are done..

        //Make sure we are null terminated
        printf("Process completed");
        break;
      case ERROR_INVALID_USER_BUFFER:
      case ERROR_NOT_ENOUGH_MEMORY:
        // Too many I/O requests pending...wait a little while
        Sleep(2000);
        break;
      default:
                                // Wierd error...return
        printf("RUNAPP ERROR: Error reading STDIO");
        break;;
      }
    }
  }
0
Comment
Question by:winkle
  • 2
  • 2
4 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 200 total points
ID: 1415057
The problem is that you have to use 'DuplicateHandle()' for each of the handles you pass to the created process, e.g.

   bStatus = CreatePipe( &hInRead, &hInWrite, NULL, 1024 );

   // ...
                                       
   bStatus = CreatePipe( &hOutRead, &hOutWrite, NULL, 1024 );

   if( ! bStatus )
   {
      CloseHandle( hInRead );          
      CloseHandle( hInWrite );
      return( FALSE );
   }
                                   /
   DuplicateHandle( GetCurrentProcess(),
                    hInWrite,
                    GetCurrentProcess(),
                    &hDupInWrite,
                    0L,
                    TRUE,
                    DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS
                  );
                                           
   DuplicateHandle( GetCurrentProcess(),
                    hOutRead,
                    GetCurrentProcess(),
                    &hDupOutRead,
                    0L,
                    TRUE,
                    DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS
                  );

   si.cb = sizeof(STARTUPINFO);
   si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
   si.wShowWindow = SW_HIDE;        
   si.hStdOut = hDupInWrite;            
   si.hStdError = hDupInWrite;
   si.hStdIn = hDupOutRead;  


0
 

Author Comment

by:winkle
ID: 1415058
I'm a little confused as to why two Createpipe calls. But I tried it and the calling process still seems to be waiting for the spawned process to be completed. Is there something different I need to be doing with my ReadFile call?

0
 

Author Comment

by:winkle
ID: 1415059
I'm a little confused as to why two Createpipe calls. But I tried it and the calling process still seems to be waiting for the spawned process to be completed. Is there something different I need to be doing with my ReadFile call?

0
 
LVL 86

Expert Comment

by:jkr
ID: 1415060
Is the spawned program a Win32 console application or a DOS program?
0

Featured Post

Get your Conversational Ransomware Defense e‑book

This e-book gives you an insight into the ransomware threat and reviews the fundamentals of top-notch ransomware preparedness and recovery. To help you protect yourself and your organization. The initial infection may be inevitable, so the best protection is to be fully prepared.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article describes a technique for converting RTF (Rich Text Format) data to HTML and provides C++ source that does it all in just a few lines of code. Although RTF is coming to be considered a "legacy" format, it is still in common use... po…
As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question