title: Connecting Anonymous Pipe across processes gives Invalid Handle Error, I'm using System.Io.Pipes
body: <p>I'm trying to put together a class to handle Ipc between processes using anonymous pipes provided by System.Io.Pipes.</p>
  
  <p>The problem I'm having is that when I test the class using a single process the pipes set up correctly and I can send data between client and server without a problem. However, when I split the client and server into separate processes ( on the same machine ), the client is unable to connect to the end of the server pipe.</p>
  
  <p>The error <strong>System.Io.Exception Invalid pipe handle</strong> is raised when call</p>
  
  <pre><code>_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);
  </code></pre>
  
  <p>The full code of the class is pasted below.</p>
  
  <p>Essentially its work like this;</p>
  
  <ol>
  <li>Server Process. Create anonymous pipe set for inbound data - call this Pipe A</li>
  <li>Server Process. Starts Client process and passes PipeHandle via command argument</li>
  <li>Client Process. Connects to end of Pipe A</li>
  <li>Client Process. Create anonymous pipe set for inbound data (Pipe B)
  5  Client process. Passes pipe handle back to Server using Pipe A</li>
  <li>Server Process. Connects to end of Pipe B</li>
  </ol>
  
  <p>So now we have two anonymous pipes, pointing in opposite directions between Server and Client.</p>
  
  <p>Here is the full code of my IPC class</p>
  
  <pre><code>    public class MessageReceivedEventArgs : EventArgs
  {
      public string Message { get; set; }
  }
  
  public class IpcChannel : IDisposable
  {
      private AnonymousPipeServerStream _inboundPipeServerStream;
      private StreamReader _inboundMessageReader;
      private string _inboundPipeHandle;
  
      private AnonymousPipeClientStream _outboundPipeServerStream;
      private StreamWriter _outboundMessageWriter;
  
      public delegate void MessageReceivedHandler(object sender, MessageReceivedEventArgs e);
      public event MessageReceivedHandler MessageReceived;
  
      private Thread _clientListenerThread;
      private bool _disposing = false;
  
      public IpcChannel()
      {
          SetupServerChannel();
      }
  
      public IpcChannel(string serverHandle)
      {
          SetupServerChannel();
          // this is the client end of the connection
  
          // create an outbound connection to the server
          System.Diagnostics.Trace.TraceInformation("Connecting client stream to server : {0}", serverHandle);
          SetupClientChannel(serverHandle);
  
          IntroduceToServer();
      }
  
      private void SetupClientChannel(string serverHandle)
      {
          _outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);
          _outboundMessageWriter = new StreamWriter(_outboundPipeServerStream)
          {
              AutoFlush = true
          };
      }
  
      private void SetupServerChannel()
      {
          _inboundPipeServerStream = new AnonymousPipeServerStream(PipeDirection.In);
          _inboundMessageReader = new StreamReader(_inboundPipeServerStream);
          _inboundPipeHandle = _inboundPipeServerStream.GetClientHandleAsString();
          _inboundPipeServerStream.DisposeLocalCopyOfClientHandle();
  
          System.Diagnostics.Trace.TraceInformation("Created server stream " + _inboundPipeServerStream.GetClientHandleAsString());
  
          _clientListenerThread = new Thread(ClientListener)
          {
              IsBackground = true
          };
  
          _clientListenerThread.Start();
  
      }
  
      public void SendMessage(string message)
      {
          System.Diagnostics.Trace.TraceInformation("Sending message {0} chars", message.Length);
  
          _outboundMessageWriter.WriteLine("M" + message);
      }
  
      private void IntroduceToServer()
      {
          System.Diagnostics.Trace.TraceInformation("Telling server callback channel is : " + _inboundPipeServerStream.GetClientHandleAsString());
  
          _outboundMessageWriter.WriteLine("CI" + _inboundPipeServerStream.GetClientHandleAsString());
      }
  
      public string ServerHandle
      {
          get
          {
              return _inboundPipeHandle;
          }
      }
  
      private void ProcessControlMessage(string message)
      {
          if (message.StartsWith("CI"))
          {
              ConnectResponseChannel(message.Substring(2));
          }
      }
  
      private void ConnectResponseChannel(string channelHandle)
      {
          System.Diagnostics.Trace.TraceInformation("Connecting response (OUT) channel to : {0}", channelHandle);
  
          _outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, channelHandle);
          _outboundMessageWriter = new StreamWriter(_outboundPipeServerStream);
          _outboundMessageWriter.AutoFlush = true;
      }
  
      private void ClientListener()
      {
          System.Diagnostics.Trace.TraceInformation("ClientListener started on thread {0}", Thread.CurrentThread.ManagedThreadId);
  
          try
          {
              while (!_disposing)
              {
                  var message = _inboundMessageReader.ReadLine();
                  if (message != null)
                  {
                      if (message.StartsWith("C"))
                      {
                          ProcessControlMessage(message);
                      }
                      else if (MessageReceived != null)
                          MessageReceived(this, new MessageReceivedEventArgs()
                          {
                              Message = message.Substring(1)
                          });
                  }
              }
          }
          catch (ThreadAbortException)
          {
          }
          finally
          {
  
          }
      }
  
      public void Dispose()
      {
          _disposing = true;
  
          _clientListenerThread.Abort();
  
          _outboundMessageWriter.Flush();
          _outboundMessageWriter.Close();
          _outboundPipeServerStream.Close();
          _outboundPipeServerStream.Dispose();
  
          _inboundMessageReader.Close();
          _inboundMessageReader.Dispose();
  
          _inboundPipeServerStream.DisposeLocalCopyOfClientHandle();
          _inboundPipeServerStream.Close();
          _inboundPipeServerStream.Dispose();
      }
  }
  </code></pre>
  
  <p>In a single process, it can be used like this;</p>
  
  <pre><code>class Program
  {
      private static IpcChannel _server;
      private static IpcChannel _client;
  
      static void Main(string[] args)
      {
          _server = new IpcChannel();
          _server.MessageReceived += (s, e) =&gt; Console.WriteLine("Server Received : " + e.Message);
  
          _client = new IpcChannel(_server.ServerHandle);
          _client.MessageReceived += (s, e) =&gt; Console.WriteLine("Client Received : " + e.Message);
  
  
          Console.ReadLine();
  
          _server.SendMessage("This is the server sending to the client");
  
          Console.ReadLine();
  
          _client.SendMessage("This is the client sending to the server");
  
          Console.ReadLine();
  
          _client.Dispose();
          _server.Dispose();
      }
  </code></pre>
  
  <p>Thanks in advance for any suggestions.</p>