C# Anonymous Pipes for Interprocess Communication

There are times when you may need to communicate between multiple processes, perhaps to send messages or share data. A recent example that I worked on involved a 64-bit application that needed to use a 32-bit DLL. The 32-bit DLL had to run in a separate process, so interprocess communication (IPC) was needed to allow the two processes to work together.

The .NET Framework provide a number of ways to perform IPC. In this post we’ll explore one such method: anonymous pipes. Anonymous pipes don’t provide as much functionality as some other methods (i.e. named pipes), and you can’t use it for communication over a network. But when you need to communicate between processes on the same computer, anonymous pipes are an excellent choice as they require less overhead.

In the “parent” (or “server”) process, we begin by creating a separate process.

The FileName property should equal the executable for the second process, and can include a full or relative path. In the code above I am assuming that “SomeOtherApp.exe” is going to be located in the same directory.

We then use the AnonymousPipeServerStream class to expose a stream around an anonymous pipe. Anonymous pipes are unidirectional, so if you need bidirectional communication, you will need two pipes. When you instantiate an AnonymousPipeServerStream, you can specify the pipe direction (in or out).

Once the anonymous pipes have been instantiated, handles to the pipes can be passed to the second process, and then that process can be started.

We then need to release the local handles that were created with the above GetClientHandleAsString calls:

If DisposeLocalCopyOfClientHandle is not called, the anonymous pipe will not receive notice when the child/client process disposes its pipe stream.

Now that the pipes have been established, we can read/write values with the other process.

In the code above I am only passing strings between the two processes, so I am using StreamWriter/StreamReader. If you had other needs, you could use something else, such as BinaryWriter/BinaryReader.

Once we’re done, we call WaitForExit and Close to end the second process that we created.

The code for the “child” (or “client”) process is similar, with a few notable exceptions. We first have to get the anonymous pipe handles that we previously passed to the second process.

Please note that we passed in the parent process’s read and then write handles, but to the second (“client”) process, the roles are reversed. The pipe that the parent process is reading from is the one that the child will be writing to, and the pipe that the parent process is writing to is the one that the child will be reading from.

Also, in the parent process we used the AnonymousPipeServerStream class. In the client process we need to use the AnonymousPipeClientStream class instead to expose a stream around an anonymous pipe. Once again, since the pipes are unidirectional, if you need bidirectional communication you will need two pipes.

In addition to the code listings that follow, all of the code for a working example is available on GitHub so you can download and run it. Here is the code for the parent/server process:

Here is the full code listing for the child/client process: