A while ago I wrote C# code to handle single instance application. And that code has served me well on Windows. However, due to its dependency on the Windows API, you really couldn't target multiplatform .NET code. It was time for an update.
My original code was using a combination of a global mutex in order to detect another instance running, followed by a named pipe communication to transfer arguments to the first-running instance. Fortunatelly, .NET 6 also contained those primitives. Even better, I could replace my named pipe API calls with multiplatform NamedPipeServerStream and NamedPipeClientStream classes.
Unlike my Windows-specific code, I had to use
Global\\ prefix in order for code to work properly on Linux. While unfortunate, it actually wasn't too bad as my mutex name already included the user name. Combine that with assembly location, hash it a bit, and you have a globally unique identifier. While the exact code was changed slightly, the logic remained the same and new code worked without much effort.
Code to transfer arguments had a few more issues. First of all, I had to swap my binary serializer for JSON. Afterward, I had to write a new pipe handling code, albeit using portable .NET implementation as a base this time. Mind you, back when I wrote it for Windows, neither has been supported. Regardless, a bit of time later, both tasks were successfuly done and the freshly updated code has been tested on Linux. Success!
But success was shortlived as the same code didn't work on Windows. Well, technically it did work but the old instance newer saw the data that was sent. It took a bit of troubleshooting to figure a basic named pipe constructor limited communication to a single process and overload setting
PipeOptions.CurrentUserOnly for both client and server was needed. Thankfuly, that didn't present any issues on Linux so the same code was good for both.
And that was it. Now I had working .NET 6 (or 7) code for a single instance application working for both Windows and Linux (probably MacOS too), allowing not only for detection but also argument forwarding. Just what I needed. :)