>Blog>Interprocess Communication: Strategies and Best Practices

Interprocess Communication: Strategies and Best Practices

July 11, 2025
cover image

We all know how challenging it is to maintain large programs and keep up with progress. Developers of plugins for Revit understand this better than anyone else. We have to write our programs in .NET Framework 4.8 and forgo modern and fast libraries. Ultimately, this affects users who are forced to use outdated software.

In such scenarios, splitting the application into multiple processes using Named Pipes appears to be an excellent solution due to its performance and reliability. In this article, we discuss how to create and use Named Pipes to communicate between the Revit application running on .NET 4.8 and its plugin running on .NET 7.

Introduction to Using Named Pipes for Communication Between Applications on Different .NET Versions

In the world of application development, there is often a need to ensure data exchange between different applications, especially in cases where they operate on different versions of .NET or different languages. Splitting a single application into multiple processes must be justified. What is simpler, calling a function directly, or exchanging messages? Obviously, the former.

So what are the benefits of doing this?

  • Resolving Dependency ConflictsWith each passing year, the size of Revit plugins is growing exponentially, and dependencies are also increasing at a geometric rate. Plugins might use incompatible versions of a single library, leading to program crashes. Process isolation solves this problem.
  • PerformanceThe performance measurements for sorting and mathematical calculations on different .NET versions are provided below.
BenchmarkDotNet v0.13.9, Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2)
AMD Ryzen 5 2600X, 1 CPU, 12 logical and 6 physical cores
.NET 7.0           : .NET 7.0.9 (7.0.923.32018), X64 RyuJIT AVX2
.NET Framework 4.8 : .NET Framework 4.8.1 (4.8.9139.0), X64 RyuJIT VectorSize=256.

How then to write a program in the latest .NET version that will interact with an incompatible .NET framework? Create two applications, Server and Client, without adding dependencies between each other and configure the interaction between them using a configured protocol.

Below are some of the possible ways of interaction between two applications:

  1. Using WCF (Windows Communication Foundation)
  2. Using sockets (TCP or UDP)
  3. Using Named Pipes
  4. Using operating system signals (e.g., Windows signals):An example from Autodesk's code, the interaction of the Project Browser plugin with the Revit backend via messages.
public class DataTransmitter : IEventObserver
{
    private void PostMessageToMainWindow(int iCmd) => 
        this.HandleOnMainThread((Action) (() => 
            Win32Api.PostMessage(Application.UIApp.getUIApplication().MainWindowHandle, 273U, new IntPtr(iCmd), IntPtr.Zero)));

    public void HandleShortCut(string key, bool ctrlPressed)
    {
        string lower = key.ToLower();
        switch (PrivateImplementationDetails.ComputeStringHash(lower))
        {
        case 388133425:
          if (!(lower == "f2")) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_RENAME);
          break;
        case 1740784714:
          if (!(lower == "delete")) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_DELETE);
          break;
        case 3447633555:
          if (!(lower == "contextmenu")) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_PROJECTBROWSER_CONTEXT_MENU_POP);
          break;
        case 3859557458:
          if (!(lower == "c") || !ctrlPressed) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_COPY);
          break;
        case 4077666505:
          if (!(lower == "v") || !ctrlPressed) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_PASTE);
          break;
        case 4228665076:
          if (!(lower == "y") || !ctrlPressed) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_REDO);
          break;
        case 4278997933:
          if (!(lower == "z") || !ctrlPressed) break;
          this.PostMessageToMainWindow(DataTransmitter.ID_UNDO);
          break;
        }
    }
}

Each option has its own pros and cons. In our opinion, the most convenient for local machine interaction is Named Pipes. Let's delve into it. Full article