After discussing this a bit with Ben Voigt, I decided to implement a process connection without using System.Diagnostics.Process. This is what I came to now, and it works great, i.e. It works sequentially every time, and nothing blocks or hangs.
I am posting this as it can help anyone who needs to read stdout / stderr and write to stdin of some created process without doing System.Diagnostics.Process.
const UInt32 STARTF_USESTDHANDLES = 0x00000100; const int HANDLE_FLAG_INHERIT = 1; struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } struct STARTUPINFO { public uint cb; public string lpReserved; public string lpDesktop; public string lpTitle; public uint dwX; public uint dwY; public uint dwXSize; public uint dwYSize; public uint dwXCountChars; public uint dwYCountChars; public uint dwFillAttribute; public uint dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } struct SECURITY_ATTRIBUTES { public int length; public IntPtr lpSecurityDescriptor; [MarshalAs(UnmanagedType.Bool)] public bool bInheritHandle; } [DllImport("kernel32.dll")] static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, uint nSize); [DllImport("kernel32", SetLastError = true)] static extern unsafe bool ReadFile(IntPtr hFile, void* pBuffer, int NumberOfBytesToRead, int* pNumberOfBytesRead, IntPtr lpOverlapped); [DllImport("kernel32.dll")] static extern unsafe bool WriteFile(IntPtr hFile, void* pBuffer, int nNumberOfBytesToWrite, int* lpNumberOfBytesWritten, IntPtr lpOverlapped); [DllImport("kernel32.dll")] static extern bool SetHandleInformation(IntPtr hObject, int dwMask, uint dwFlags); void OpenAndCloseFcsh() { STARTUPINFO si = new STARTUPINFO(); SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); sa.bInheritHandle = true; sa.lpSecurityDescriptor = IntPtr.Zero; sa.length = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)); sa.lpSecurityDescriptor = IntPtr.Zero; IntPtr h_stdout_r, h_stdout_w; if (!CreatePipe(out h_stdout_r, out h_stdout_w, ref sa, 0)) throw new Exception("bad"); if (!SetHandleInformation(h_stdout_r, HANDLE_FLAG_INHERIT, 0)) throw new Exception("bad"); IntPtr h_stdin_r, h_stdin_w; if (!CreatePipe(out h_stdin_r, out h_stdin_w, ref sa, 0)) throw new Exception("bad"); if (!SetHandleInformation(h_stdin_w, HANDLE_FLAG_INHERIT, 0)) throw new Exception("bad"); si.wShowWindow = 0; si.cb = (uint)Marshal.SizeOf(si); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdOutput = h_stdout_w; si.hStdError = h_stdout_w; si.hStdInput = h_stdin_r; string command = @"C:\flex_sdks\flex_sdk_4.5.1.21328_trimmed\bin\fcsh.exe"; if (!CreateProcess(command, null, IntPtr.Zero, IntPtr.Zero, true, 0, IntPtr.Zero, null, ref si, out pi)) throw new Exception("bad"); Console.WriteLine("Process ID (PID): " + pi.dwProcessId); Console.WriteLine("Process Handle : " + pi.hProcess);