Solved

Reading from a pipe

Posted on 1998-10-07
4
1,916 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
4 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 100 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

SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.

Question has a verified solution.

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

This article shows how to make a Windows 7 gadget that accepts files dropped from the Windows Explorer.  It also illustrates how to give your gadget a non-rectangular shape and how to add some nifty visual effects to text displayed in a your gadget.…
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…
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…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…

717 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