title: Asynchronous I/O with Named Pipes WinAPI
body: <p>Ok, I have asked a few questions about different facets of trying to accomplish what I want to do. This time I'm having big issues just reading from a named pipe. I think I have harvested enough information to possibly complete the project I am working on if I can set this up properly. I will include all relevant code below, but my mission is this: read the output (continuously) from a program I did <em>not</em> write and post it to the WinAPI. So my problem is that I have just switched from anonymous pipes to named pipes and I am having issues trying to properly set them up so I can retrieve information. I have a framework setup based off of an example from the MSDN.</p>
  
  <pre><code>#define WAIT_TIME 2 // 2s
  #define INSTANCES 4 // Number of threads
  #define CONNECT_STATE 0
  #define READ_STATE 1
  #define WRITE_STATE 2
  #define WORLDRD 0
  #define WORLDWR 1
  #define WORLDINRD 2
  #define WORLDINWR 3
  #define BUFSIZE 0x1000 // Buffer size 4096 (in bytes)
  #define PIPE_TIMEOUT 0x1388 // Timeout 5000 (in ms)
  
  void Arc_Redirect::createProcesses()
  {
  TCHAR programName[]=TEXT("EXEC_PROGRAM.exe");
  PROCESS_INFORMATION pi; 
  STARTUPINFO si;
  BOOL bSuccess = FALSE; 
  
  ZeroMemory(hEvents,(sizeof(hEvents)*INSTANCES));
  ZeroMemory(outStd,(sizeof(PIPE_HANDLES)*INSTANCES));
  
  // Prep pipes
  for(int i=0;i&lt;INSTANCES;i++)
  {
      hEvents[i] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
  
      if(hEvents[i] == NULL)
          throw "Could not init program!";
  
      outStd[i].o1.hEvent = hEvents[i];
  
      outStd[i].hPipeInst = ::CreateNamedPipe(
          TEXT("\\\\.\\pipe\\arcworld"), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
          PIPE_UNLIMITED_INSTANCES, BUFSIZE*sizeof(TCHAR), BUFSIZE*sizeof(TCHAR), PIPE_TIMEOUT, NULL);
  
      if(outStd[i].hPipeInst == INVALID_HANDLE_VALUE)
          throw "Could not init program!";
  
      outStd[i].pendingIO = getState(outStd[i].hPipeInst,&amp;outStd[i].o1);
  
      outStd[i].dwState = outStd[i].pendingIO ?
          CONNECT_STATE : READ_STATE;
  }
  
  // Set stuff up
  ZeroMemory( &amp;pi, sizeof(PROCESS_INFORMATION));
  ZeroMemory( &amp;si, sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO); 
  si.hStdError = outStd[WORLDRD].hPipeInst;
  si.hStdOutput = outStd[WORLDRD].hPipeInst;
  si.hStdInput = outStd[WORLDINWR].hPipeInst;
  si.dwFlags |= STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES|FILE_FLAG_OVERLAPPED;
  
      // Start our process with the si info
  CreateProcess(programName,NULL,NULL,NULL,FALSE,0,NULL,NULL,&amp;si,&amp;pi);
  }
  
  BOOL Arc_Redirect::getState(HANDLE hPipe, LPOVERLAPPED lpo)
  {
      BOOL connected, pendingIO = FALSE;
  
      // Overlap connection for this pipe
      connected = ::ConnectNamedPipe(hPipe,lpo);
  
      if(connected)
          throw "ConnectNamedPipe(); failed!";
  
      switch(GetLastError())
      {
          case ERROR_IO_PENDING:
              pendingIO = TRUE;
          break;
          case ERROR_PIPE_CONNECTED:
              if(SetEvent(lpo-&gt;hEvent))
                  break;  
          default:
              throw "ConnectNamedPipe(); failed!";
          break;
      }
  
      return pendingIO;
  }
  </code></pre>
  
  <p>outStd[INSTANCES] is defined as PIPE_HANDLES (a custom struct) which is below</p>
  
  <pre><code>typedef struct
  {
      HANDLE hPipeInst;
      OVERLAPPED o1;
      TCHAR chReq[BUFSIZE];
      TCHAR chReply[BUFSIZE];
      DWORD dwRead;
      DWORD dwWritten;
      DWORD dwState;
      DWORD cbRet;
      BOOL pendingIO;
  } PIPE_HANDLES, *LPSTDPIPE;
  </code></pre>
  
  <p>Now from here is where I am getting a bit lost. I'm not sure where to go. I tried using the loop in the MSDN example, but it didn't work properly for what I am looking to do. I need to take the read end of the pipe and retrieve the information (again, continuously) while having a write end opened as well for whenever I may need to write to it. Does anyone have any ideas? I have been trying to do a ReadFile() as I would do with an anonymous pipe, but it does not appear to be working in the same fashion.</p>
  
  <p>Also, please note: The code is a bit sloppy because I have been working with it, so I apologize. I will definitely be cleaning it up after I get this to function properly.</p>