Reading from a pipe via ReadFile [WinAPI]

 

Trying to run cmd.exe as a child process and read standard output from it, but the ReadFile function results in error 109 (ERROR_BROKEN_PIPE). What am I missing here?

#define BUFFER_SIZE 16
#define ERROR_MORE_DATA 234

#include <WinAPI\sysinfoapi.mqh>
#include <WinAPI\processthreadsapi.mqh>
#include <WinAPI\handleapi.mqh>
#include <WinAPI\errhandlingapi.mqh>

struct SecurityAttributes {
  ulong Length;
  long  SecurityDescriptor;
  bool  InheritHandle;
};

#import "kernel32.dll"
   int CreatePipe(
      long& readPipe,
      long& writePipe,
      SecurityAttributes& pipeAttributes,
      ulong size);
#import

enum ProcessCreationFlags {
   CREATE_NO_WINDOW   = 0x08000000,
   CREATE_NEW_CONSOLE = 0x00000010
};

enum HandlePropertyFlags {
   HANDLE_FLAG_INHERIT = 0x00000001
};

enum StartupInfoFlags {
   STARTF_USESTDHANDLES = 0x00000100
};

void OnStart()
  {
   ushort systemDirectoryArray[256];
   if(0 == GetSystemDirectoryW(systemDirectoryArray, systemDirectoryArray.Size()))
     {
      printLastError("GetSystemDirectoryW ERROR: ");
      return;
     }
     
   SecurityAttributes securityAttributes {
      sizeof(SecurityAttributes),
      NULL,
      true
   };
   bool pipesOk = true;
   
   // pipe for the child process' stdin
   long inReadPipeHandle = 0;
   long inWritePipeHandle = 0;
   if(0 != CreatePipe(inReadPipeHandle, inWritePipeHandle, securityAttributes, 0))
     {
      if(0 == SetHandleInformation(
         inWritePipeHandle, 
         HandlePropertyFlags::HANDLE_FLAG_INHERIT, 
         0))
        {
         printLastError("SetHandleInformation IN error: ");
         pipesOk = false;
        }
     }
   else
     {
      printLastError("CreatePipe IN error: ");
      inReadPipeHandle = 0;
      inWritePipeHandle = 0;
      pipesOk = false;
     }
   
   // pipe for the child process' stdout
   long outReadPipeHandle = 0;
   long outWritePipeHandle = 0;
   if(pipesOk)
     {
      if(0 != CreatePipe(outReadPipeHandle, outWritePipeHandle, securityAttributes, 0))
        {
         if(0 == SetHandleInformation(
            outReadPipeHandle, 
            HandlePropertyFlags::HANDLE_FLAG_INHERIT, 
            0))
           {
            printLastError("SetHandleInformation OUT error: ");
            pipesOk = false;
           }
        }
      else
        {
         printLastError("CreatePipe OUT error: ");
         outReadPipeHandle = 0;
         outWritePipeHandle = 0;
         pipesOk = false;
        }
     }
     
   if(pipesOk)
     {
      STARTUPINFOW startupInfo;
      ZeroMemory(startupInfo);
      startupInfo.cb = sizeof(STARTUPINFOW);
      startupInfo.hStdError = outWritePipeHandle;
      startupInfo.hStdOutput = outWritePipeHandle;
      startupInfo.hStdInput = inReadPipeHandle;
      startupInfo.dwFlags |= StartupInfoFlags::STARTF_USESTDHANDLES;
      
      PROCESS_INFORMATION processInfo;
      ZeroMemory(processInfo);
      
      const string cmdPath = ShortArrayToString(systemDirectoryArray) + "\\cmd.exe";
      const string commandLine = "/c echo hello";
      if(CreateProcessW(
         cmdPath,
         commandLine,
         NULL,
         NULL,
         1,
         0,
         NULL,
         NULL,
         startupInfo,
         processInfo))
        {          
         closeHandleSafely(processInfo.hProcess, "hProcess");
         closeHandleSafely(processInfo.hThread, "hThread");
         closeHandleSafely(outWritePipeHandle, "outWritePipeHandle");
         closeHandleSafely(inReadPipeHandle, "inReadPipeHandle");
           
         string result = "";
         uint readBytes = 0;
         ushort buffer[BUFFER_SIZE] = {0};
         do
           {
            int readResult = ReadFile(
               outReadPipeHandle,
               buffer, 
               BUFFER_SIZE - 1, 
               readBytes, 
               NULL);
            if(0 == readResult)
              {
               uint readErrorCode = 0;
               printLastError("ReadFile error: ", readErrorCode);
               if(readErrorCode != ERROR_MORE_DATA)
                 {
                  break;
                 }
              }
            else
              {
               if (0 == readBytes)
                 {
                  Print("No more data to read");
                  break;
                 }
               else
                 {
                  result += ShortArrayToString(buffer);
                  Print("Read ", readBytes, " bytes");
                 }
              }
           }
         while(true);
           
         if("" == result)
           {
            Print("No result");
           }
         else
           {
            Print("Result: ", result);
           }
        }
      else
        {
         printLastError("CreateProcessW error: ");
        }
     }
     
   closeHandleSafely(outWritePipeHandle, "outWritePipeHandle");
   closeHandleSafely(inReadPipeHandle, "inReadPipeHandle"); 
   closeHandleSafely(inWritePipeHandle, "inWritePipeHandle");
   closeHandleSafely(outReadPipeHandle, "outReadPipeHandle");
     
   Print("Finished");
  }
  
void closeHandleSafely(long& handle, const string handleName)
  {
   if(0 != handle)
     { 
      if(0 == CloseHandle(handle))
        {
         printLastError("CloseHandle " + handleName + " error: ");
        }
      else
        {
         handle = 0;
        }
     }
  }
  
void printLastError(const string message)
  {
   printErrorCode(message, kernel32::GetLastError());
  }
void printLastError(const string message, uint& lastError)
  {
   lastError = kernel32::GetLastError();
   printErrorCode(message, lastError);
  }
void printErrorCode(const string message, const uint errorCode)
  {
   Print(message, errorCode);
  }