Effective Communication Between Executable Files Using Shared Memory

In a WPF (Windows Presentation Foundation) application, inter-process connectivity typically involves communication between different components or modules within the same application or between separate WPF applications running on the same system or across different systems.

There are various methods to achieve inter-process communication (IPC) in WPF.

  1. Named Pipes: Named pipes enable two processes to communicate by creating a pipe with a specific name. WPF applications can utilize named pipes to establish communication between them. .NET offers classes such as NamedPipeServerStream and NamedPipeClientStream for handling named pipes.
  2. WCF (Windows Communication Foundation): WCF is a framework designed for constructing service-oriented applications. WPF applications can employ WCF to communicate with other applications or services through different transport protocols like TCP/IP, HTTP, named pipes, etc.
  3. Shared Memory: WPF applications can share data through shared memory mechanisms like memory-mapped files. This enables multiple processes to access the same memory region.

Using shared memory mechanisms like memory-mapped files in WPF applications allows multiple processes to access the same memory region, facilitating efficient inter-process communication. Here's an explanation of it.

Advantages

  1. High Performance: Shared memory ensures high performance by directly sharing memory between processes, eliminating the need for serialization and deserialization present in other IPC mechanisms like pipes or sockets.
  2. Low Latency: Communication latency is minimized as data is shared directly in memory, making it ideal for scenarios requiring quick data exchange between processes.
  3. Synchronization: Shared memory mechanisms often include synchronization primitives such as mutexes, semaphores, or locks to coordinate access to shared resources, ensuring data integrity and preventing race conditions.
  4. Scalability: Shared memory can effectively scale to support communication between multiple processes, making it suitable for scenarios where collaboration or data sharing among processes is necessary.
  5. Memory Efficiency: Shared memory consumes less memory compared to other IPC mechanisms as it avoids the overhead of copying data between processes.

Disadvantages

  1. Complexity: Implementing shared memory communication requires careful management of memory regions, synchronization primitives, and data structures, which can be intricate and prone to errors.
  2. Platform Dependency: Shared memory mechanisms may have platform-specific implementations and behavior, reducing application portability across different operating systems.
  3. Security Concerns: Improper management of shared memory can introduce security vulnerabilities, potentially leading to data leaks or corruption through unauthorized access to shared memory regions.
  4. Lifetime Management: Proper management of shared memory regions in terms of creation, allocation, and deallocation is crucial to avoid memory leaks or fragmentation.
  5. Resource Contentions: Concurrent access to shared memory regions by multiple processes can result in resource contentions and bottlenecks, impacting overall system performance.

Shared memory mechanisms like memory-mapped files offer high performance and low latency for inter-process communication.

I have incorporated the Shared memory process within the WPF application. To successfully implement this, you must adhere to the subsequent steps.

Step 1. Develop a project similar to the one outlined below.

Develop a project

Step 2. To facilitate collaboration between the "Memory Writer" and "Memory Reader", a shared project needs to be established. To address this requirement, I have developed a project called "CommonLib". Its purpose is to enable seamless communication and cooperation between the Memory Writer and Memory Reader.

using System.IO.MemoryMappedFiles;

namespace CommonLib
{
    public class CommonHelper
    {
        public MemoryMappedFile memoryMappedFile;

        // Private static instance variable to hold the single instance of the class
        private static CommonHelper instance;

        // Private static object for locking
        private static readonly object lockObject = new object();

        // Private constructor to prevent instantiation from outside the class
        private CommonHelper()
        {
            memoryMappedFile = MemoryMappedFile.CreateOrOpen("SharedMemory", 10000);
        }

        // Public static method to provide access to the single instance of the class
        public static CommonHelper GetInstance()
        {
            // Double-check locking to ensure thread safety
            if (instance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new CommonHelper();
                    }
                }
            }
            return instance;
        }
    }
}

Step 3. Develop a “Memory Reader” that will receive messages from memory.

XAML View

<Window x:Class="SharedMemoryReader.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SharedMemoryReader"
        mc:Ignorable="d"
        Title="Read" Height="550" Width="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <Button Content="Read From Shared Memory" Height="50" Click="Button_Click" Margin="10"/>
            <TextBox Foreground="DarkGreen" FontSize="30" FontWeight="Bold" x:Name="TxtbxMessageReceived" Height="300" BorderBrush="Gray" BorderThickness="2" Margin="10"/>
        </StackPanel>
    </Grid>
</Window>

Code Behind

using CommonLib;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SharedMemoryReader
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MemoryMappedFile memoryMappedFile = CommonHelper.GetInstance().memoryMappedFile;
            using (MemoryMappedViewAccessor accessor = memoryMappedFile.CreateViewAccessor())// Create a memory-mapped view accessor
            {
                // Read data from shared memory
                byte[] buffer = new byte[10000];
                accessor.ReadArray(0, buffer, 0, buffer.Length);
                string message = Encoding.ASCII.GetString(buffer).Trim('\0');
                TxtbxMessageReceived.Text = message;
            }
        }
    }
}

Read

Step 4. Develop a “Memory Writer” that will write messages to the memory.

XAML View

<Window x:Class="SharedMemoryWriter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SharedMemoryWriter"
        mc:Ignorable="d"
        Title="Write" Height="550" Width="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <Button Content="Write to Shared Memory" Height="50" Click="Button_Click" Margin="10"/>
            <TextBox Foreground="Red" FontSize="30" FontWeight="Bold" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" AcceptsTab="True" x:Name="TxtBxMessage" Height="300" Margin="10" BorderBrush="Gray" BorderThickness="2"/>
            <TextBlock x:Name="TxtBlckInformation" FontSize="20" FontWeight="Bold" Height="30" Margin="10" />
        </StackPanel>
    </Grid>
</Window>

Code Behind

using CommonLib;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Windows;

namespace SharedMemoryWriter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MemoryMappedFile memoryMappedFile = CommonHelper.GetInstance().memoryMappedFile;
            using (MemoryMappedViewAccessor accessor = memoryMappedFile.CreateViewAccessor())
            {
                // Write data to shared memory
                byte[] buffer = Encoding.ASCII.GetBytes(TxtBxMessage.Text);
                accessor.WriteArray(0, buffer, 0, buffer.Length);
                TxtBlckInformation.Text = "Data written to shared memory";
            }
        }
    }
}

Write

Step 5. Visual Presentation in Operation.

 Visual Presentation

Repository Path: https://github.com/OmatrixTech/SharedMemoryExample