Blog

Minimalist Interprocess Communication

There are many options in .NET for interprocess communication. If you own one process that is starting another, you can use console I/O as a minimalist IPC.

Applicability

This approach only works if your own code is launching the other process. There is no convenient way to attach to an already running process and redirect it’s standard I/O in .NET. The child process needs to be something that already uses console I/O or something you can modify.

The parent and child process can either be a GUI or Console application (any mix). Standard and Core .NET are supported.

If these limitations are too restrictive, consider the NamedPipeServerStream as the next step up or review the broader set of IPC options in Windows.

Starting the Process

    ProcessStartInfo startInfo = new ProcessStartInfo(path);
    startInfo.UseShellExecute = false; // required to redirect I/O
    startInfo.RedirectStandardInput = true;
    startInfo.RedirectStandardOutput = true;

    Process process = Process.Start(startInfo);

If the child is a console application, it can be useful to add this line to hide the console window:

	startInfo.CreateNoWindow = true;

Side Note: Access Denied

If you accidentally try to use a directory path when calling Process.Start, you will get a Win32 AccessDenied exception. This is misleading since no amount of Administrator permission will solve it. It may help your sanity to check Directory.Exists(path) and throw your own exception before calling Process.Start.

Communication

You have the option of synchronous or asynchronous communication. This choice can be made independently for the parent and child process. Consider isolating all of this in a shared library so that both parent and child processes only see plain old C# method calls.

Remember that the child process is not required to be a Console project in order to use Console class methods.

Synchronous

If I am already running in another thread I will tend toward the simplicity of synchronous calls. The ReadLine method will block until data is received. Also beware that WriteLine can block if the child application’s receive buffer is full.

	// From the parent process
	_process.StandardInput.WriteLine("Hello from parent");
	string line = _process.StandardOutput.ReadLine();
	
	// From the child process
	string line = Console.ReadLine();
	Console.WriteLine("Echo " + line);

Asynchronous

Async from the parent process is straightforward:

	// From the parent process
	await _process.StandardInput.WriteLineAsync("Async hello from parent");
	string line = await _process.StandardOutput.ReadLineAsync();

But there are no read/write async methods on the Console class so we have to wrap them with Task:

	
	// From the child process
	string line = await Task.Run(() => Console.ReadLine());
	await Task.Run(() => Console.WriteLine("Echo " + line));

You will need to select C# 7.1 or higher to use an async Main method within a Console project.

Featured Image Credit

Phidget SBC, photo by Nick Bushby