Two WinForms applications that exchange an image across processes using a named MemoryMappedFile and a named AutoReset event. Image data is handled with OpenCvSharp and displayed in PictureBox controls.
- .NET target : .NET Framework 4.8
- Language : C# 7.3
- UI : Windows Forms (WinForms)
- Libraries : OpenCvSharp, OpenCvSharp.Extensions
Projects :
- SharedMemorySender (namespace : SharedMemoryTest)
- SharedMemoryReceiver (namespace : SharedMemoryReceiver)
The sender loads an image into an OpenCvSharp Mat, writes a small header followed by the raw pixel bytes to a named memory-mapped file, then signals a named event. The receiver waits on the event, reads the header and data from the same memory, reconstructs the Mat, and displays it.
Named objects (must match exactly in both apps) :
- Memory-mapped file name :
SharedMemoryTest - Event name :
SharedMemoryTest_ImageReady
Shared memory layout (byte offsets) :
- Header (5 x 32-bit integers, 20 bytes total)
- type (int) OpenCV Mat type (e.g., CV_8UC3), written as
mat.Type() - step (int) stride in bytes per row, written as
(int)mat.Step() - width (int)
mat.Cols - height (int)
mat.Rows - dataSize(int) total raw byte size =
mat.Total() * mat.ElemSize()
- type (int) OpenCV Mat type (e.g., CV_8UC3), written as
- Pixel data (
dataSizebytes) : raw copy ofmat.Data
Memory limits :
- Sender allocates 100 MB for the shared memory.
- Sender rejects images if
HeaderSize + dataSize > 100 MB. - Receiver rejects payloads if width <= 0, height <= 0, dataSize <= 0, or dataSize > 90 MB.
Note : Data is uncompressed raw bytes; the receiver constructs the Mat with new Mat(height, width, (MatType)type) and copies the bytes into it.
- Windows with .NET Framework 4.8
- Visual Studio 2022
- NuGet packages :
- OpenCvSharp
- OpenCvSharp.Extensions
- Open the solution in Visual Studio 2022.
- Restore NuGet packages (e.g., from Solution Explorer or the Manage NuGet Packages UI).
- Build the solution (Build).
Both projects are WinForms apps targeting .NET Framework 4.8.
You need both apps running to see inter-process image transfer.
Order considerations :
- Sender creates or opens the shared memory and event on startup.
- Receiver opens existing objects only when you click Start. If the sender has not created them yet, Start will fail with "Start failed : ...".
- Practical guidance : Start the sender first, or start the receiver but click Start only after the sender has launched.
Controls :
- Load image (btnLoad)
- Show image (btnShow)
- PictureBox (630 x 420, StretchImage)
- StatusStrip (RoyalBlue) with labels :
- Status, Width, Height, Type, Size, KB Step
Behavior :
-
Load image :
- Opens a file dialog filtered to :
*.jpg;*.jpeg;*.jpe;*.jfif;*.png;*.tif;*.bmp - Loads the file with
ImreadModes.UnchangedintoMat. - Calculates header values :
type = mat.Type()step = (int)mat.Step()width = mat.Colsheight = mat.RowsdataSize = (int)(mat.Total() * mat.ElemSize())
- Writes header + data to the memory-mapped file (offset 0 for header, then pixels).
- Flushes the accessor and signals the event.
- Updates UI :
- Displays the loaded image in the sender’s PictureBox.
- Status text set to "Image loaded".
- Width / Height / Type / KB Step shown from header.
- Size label shows
dataSize / 1024(numeric value, no "KB" suffix).
- If the image does not fit : sets Status to "Image too large for shared memory." and aborts.
- Opens a file dialog filtered to :
-
Show image :
- Reads back the current header and data from the same shared memory (local verification).
- Reconstructs a
Matfrom the memory and displays it locally.
-
Form close : disposes the event and memory-mapped file.
DPI handling :
- On Load, measures current DPI and sets the Status label width to a DPI-scaled value (approx. 630 px at 100% scaling).
Controls :
- Start (btnStart)
- Stop (btnStop)
- Save Image (btnSave)
- Clear (btnClear)
- Oneshot Mode (chkOneShot)
- PictureBox (630 x 420, StretchImage)
- StatusStrip (green) with labels :
- Status, Width, Height, Type, Size, KB Step
Behavior :
-
Start :
- Opens existing memory-mapped file for read and existing event.
- Sets "one-shot" mode based on checkbox.
- Disables Start and checkbox; Stop is disabled in one-shot mode and enabled otherwise.
- Status label width is set to a small or large size depending on whether an image is already displayed, then text set to "Waiting (one shot)" or "Waiting for images...".
- Starts a background receive loop.
-
Receive loop :
- Waits up to 500 ms for the event. On signal, reads the header and data.
- Validates header and data size (width, height, 0 < dataSize ≤ 90 MB).
- Constructs a
Mat, copies bytes, replaces the current Mat under a lock. - On UI thread :
- Converts to
Bitmapand displays in PictureBox. - Enables Save.
- Updates Width / Height / Type / KB Step / Size (Size shows
<KB> KBwith unit).
- Converts to
- In one-shot mode, stops after the first image and sets Status to "One shot received".
-
Stop :
- Stops receiving; re-enables Start and checkbox; sets Status to "Stopped".
-
Save Image :
- Clones the current Mat under a lock and opens a SaveFileDialog :
- Filter : PNG / JPEG / BMP / TIFF
- Default filename :
received.png
- Saves with
Mat.SaveImage(). On success, Status set to "Saved : ". On failure, Status set to "Save failed : ".
- Clones the current Mat under a lock and opens a SaveFileDialog :
-
Clear :
- Disposes current Mat and clears the PictureBox.
- Disables Save.
- Status set to "Cleared".
-
Error handling :
- Any read / display errors set Status accordingly (e.g., "Invalid header", "Error : ...", "Display failed : ...").
DPI handling :
- On Load and on DPI change (DpiChanged, DpiChangedBeforeParent, DpiChangedAfterParent), measures current DPI and updates internal DPI values.
- The Status label width is toggled between two DPI-scaled widths (approx. 130 px for compact and 630 px for expanded) depending on context.
Cleanup :
- The receiver defines a
Form1_FormClosedmethod that stops the loop and disposes resources (event, memory, Mat). The DPI change events are wired; the FormClosed handler is defined in code but is not wired in the designer.
Constants :
- Memory-mapped file name :
SharedMemoryTest - Event name :
SharedMemoryTest_ImageReady - Sender shared memory size :
100 * 1024 * 1024bytes - HeaderIntCount :
5 - HeaderSize :
sizeof(int) * 5(20 bytes)
Sender writes :
- Header :
{ type, step, width, height, dataSize } - Data :
byte[dataSize]copied frommat.Data
Receiver reconstructs :
new Mat(height, width, (MatType)type)Marshal.Copy(buffer, 0, mat.Data, dataSize)
Field meanings as displayed in the UI :
- Type : raw OpenCV Mat type integer (
Mat.Type()) - KB Step : row stride in bytes (
(int)mat.Step()) - Size : in KB; receiver shows with " KB" suffix; sender shows number only
- Width / Height : in pixels
- Single payload buffer; each new image overwrites the previous content.
- No versioning; both processes must agree on the header format.
- The receiver ignores
stepfor reconstruction and assumes the provided buffer fitsheight * width * elemSize. - The event is AutoReset; one waiting receiver is released per signal.
- The receiver enforces a stricter dataSize upper bound (90 MB) than the sender’s allocation (100 MB).
SharedMemorySender :
- Buttons : Load image, Show image
- PictureBox : shows the loaded or read-back image
- Status : "Image loaded", errors like "Image too large for shared memory."
- Status strip color : RoyalBlue
SharedMemoryReceiver :
- Buttons : Start, Stop, Save Image, Clear
- Checkbox : Oneshot Mode
- PictureBox : shows the received image
- Status : "Waiting for images...", "Waiting (one shot)", "One shot received", "Stopped", "Cleared", failures as described
- Status strip color : green