title: Asynchronous output redirection in Win32
body: <p>This is about launching a child process and redirecting output.</p>
  
  <p>In .NET, we could use Process.RedirectStandard... to redirect the standard IO, and use Process.OutputDataReceived to receive an event when something was written to the output.</p>
  
  <p>I want to implement this in native C++ with Win32 API.</p>
  
  <p>As I looked into the source (<a href="http://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/Process.cs,2566" rel="nofollow noreferrer">1</a>, <a href="http://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/AsyncStreamReader.cs,141" rel="nofollow noreferrer">2</a>), it looks like it's using <a href="https://msdn.microsoft.com/en-us/library/system.io.stream.beginread(v=vs.110).aspx" rel="nofollow noreferrer">Stream.BeginRead</a> method, but I couldn't find out how this method is implemented.</p>
  
  <p>I assume that it's using <em>busy-waiting</em> by making a new thread (or a Task in .NET), but if so, I want to know how many second it <em>Sleep</em>s per loop (since Sleep(0) boosts my cpu fan).</p>
  
  <p>Here's the code which I assume how it would look like:</p>
  
  <pre><code>HANDLE hOutputRead;
  typedef void (*UserCallback)(size_t);
  UserCallback OutputDataReceived;
  void *Buffer;
  
  bool exec(UserCallback callback, void *buffer /* string written to stdout */)
  {
      OutputDataReceived = callback;
      Buffer = buffer;
  
      SECURITY_ATTRIBUTES sa;
      sa.nLength = sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;
  
      HANDLE hOutputReadTemp, hOutputWrite;
  
      CreatePipe(&amp;hOutputReadTemp, &amp;hOutputWrite, &amp;sa, 0);
  
      DuplicateHandle(
          GetCurrentProcess(), hOutputReadTemp,
          GetCurrentProcess(), hOutputRead,
          0, FALSE, DUPLICATE_SAME_ACCESS
      )   // to prevent hOutputReadTemp from being inherited to the launched process, 
          // we duplicate to hOutputRead with no inheritance priviledge, 
      CloseHandle(hOutputReadTemp);   // and close the original.
  
      STARTUPINFO si = {};
      si.cb = sizeof(STARTUPINFO);
      si.dwFlags = STARTF_USESTDHANDLES;
      si.hStdOutput = hOutputWrite;
  
      PROCESS_INFORMATION pi;
      if (!CreateProcess(NULL, "C:\\path\\to\\child.exe", NULL, NULL, TRUE, 0, NULL, NULL, &amp;si, &amp;pi))
          return false;
  
      CloseHandle(pi.hThread);
      CloseHandle(hOutputWrite);  // we won't be using this handle anymore
  
      CreateThread(NULL, 0, CheckPipeAsync, NULL, 0, NULL);
  }
  
  DWORD WINAPI CheckPipeAsync(LPVOID lpParameter) // if anything gets written to output, call OutputDataReceived()
  {
      int size;
  
      while (PeekNamedPipe(hOutputRead, NULL, NULL, NULL, &amp;size, NULL))  // busy wait
      {
          if (size == 0) // nothing written
          {
              Sleep(TIME_TO_SLEEP_PER_LOOP);
              continue;
          }
  
          DWORD bytesRead;
          ReadFile(hOutputRead, Buffer, size, &amp;bytesRead, NULL);
          OutputDataReceived(size);   // callback when something was written to stdout
      }
  
      return TRUE;
  }
  </code></pre>
  
  <p><a href="https://support.microsoft.com/en-us/help/190351/how-to-spawn-console-processes-with-redirected-standard-handles" rel="nofollow noreferrer">reference (How to spawn console processes with redirected standard handles)</a></p>
  
  <p>Please pardon my poor English.</p>