title: How does one setup a pipe between two child processes in Win32?
body: <p>For the life of me I can't figure out why this is not working. Basically, I created the pipe with the inherit bit set to true, and created two child processes, and used the STARTUPINFO structure to set the input and output handles as one would need, but the pipe seems broken (the second process writes no output to the console, even though output is expected)</p>
  
  <p>I know the problem does not lie in my test program (<code>BitTwiddler.exe</code>) because I performed the same operation using CMD.exe, and everything works as expected.</p>
  
  <p>Below is a minimal reproduction of what I have. What have I done incorrectly?</p>
  
  <pre><code>#include "windows.h"
  
  int main()
  {
      PROCESS_INFORMATION piSource, piDest;
      HANDLE hPipeIn, hPipeOut;
      HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
      HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
      STARTUPINFOW suSource, suDest;
      ZeroMemory(&amp;suSource, sizeof(suSource));
      ZeroMemory(&amp;suDest, sizeof(suDest));
      suSource.cb = suDest.cb = sizeof(STARTUPINFOW);
      suSource.dwFlags = suDest.dwFlags = STARTF_USESTDHANDLES;
      SECURITY_ATTRIBUTES sa;
      sa.nLength = sizeof(sa);
      sa.lpSecurityDescriptor = 0;
      sa.bInheritHandle = TRUE;
      if (CreatePipe(&amp;hPipeIn, &amp;hPipeOut, &amp;sa, 0) == 0)
      {
          return GetLastError();
      }
      suSource.hStdInput = hIn;
      suSource.hStdError = suSource.hStdOutput = hPipeIn;
      suDest.hStdInput = hPipeOut;
      suDest.hStdError = suDest.hStdOutput = hOut;
      std::wstring cmdLineA(L"BitTwiddler 1"), cmdLineB(L"BitTwiddler 0");
      cmdLineA.push_back(0); cmdLineB.push_back(0);
      if (CreateProcessW(0, &amp;cmdLineA[0], 0, 0, TRUE, 0, 0, 0, &amp;suSource, &amp;piSource) == 0)
      {
          return GetLastError();
      }
      CloseHandle(piSource.hThread);
      if (CreateProcessW(0, &amp;cmdLineB[0], 0, 0, TRUE, 0, 0, 0, &amp;suDest, &amp;piDest) == 0)
      {
          return GetLastError();
      }
      CloseHandle(piDest.hThread);
      HANDLE hArray[2];
      hArray[0] = piSource.hProcess;
      hArray[1] = piDest.hProcess;
      WaitForMultipleObjects(2, hArray, TRUE, INFINITE);
      CloseHandle(hArray[0]);
      CloseHandle(hArray[1]);
      return 0;
  }
  </code></pre>
  
  <p>(In case anyone's interested, BitTwiddler is:</p>
  
  <pre><code>#include &lt;windows.h&gt;
  #include &lt;sstream&gt;
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  
  int main(int argc, char *argv[])
  {
      std::size_t opt = 0;
      argc--; argv++;
      if (argc == 0)
      {
          return 0;
      }
      else
      {
          std::istringstream converter(*argv);
          converter &gt;&gt; opt;
      }
      switch(opt)
      {
      case 0:
          {
              std::wstring currentLine;
              while(std::getline(std::wcin, currentLine))
              {
                  std::wcout &lt;&lt; "Got somepin: " &lt;&lt; currentLine &lt;&lt; std::endl;
              }
          }
          break;
      case 1:
          for (;;)
          {
              std::wcout &lt;&lt; L"Hello World!" &lt;&lt; std::endl;
              Sleep(1000);
          }
          break;
      case 2:
          return -1;
      default:
          std::wcout &lt;&lt; "Unknown option.";
          return 0;
      }
      return 0;
  }
  </code></pre>
  
  <p>), but I really don't think that matters.</p>