?
Solved

Reading from a pipe

Posted on 1998-10-07
4
Medium Priority
?
1,920 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 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

Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

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.…
zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
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…
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…

650 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