首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET Compact Framework IPC 方案二:Windows Message 跨進程通信與對象傳遞

     編輯:關於.NET

除 MSMQ,Windows CE 原生 **Windows Message** 機制 (`coredll.dll`) 也是輕量級 IPC 選擇:無需額外服務、延遲極低、支持廣播與對象封送 (WM_COPYDATA)。本文講解 CF.NET 中 `Microsoft.WindowsCE.Forms.MessageWindow` 封裝、自定義消息註冊、字符串/對象傳遞 (COPYDATASTRUCT) 完整實現。

基礎:註冊唯一消息 ID

using Microsoft.WindowsCE.Forms;
using System.Runtime.InteropServices;

[DllImport("coredll.dll", EntryPoint = "RegisterWindowMessage", SetLastError = true)]
private static extern uint RegisterWindowMessage(string lpString);

private static readonly uint MsgId = RegisterWindowMessage("MY_APP_UNIQUE_MSG_ID");
private const int HWND_BROADCAST = 0xFFFF;

`RegisterWindowMessage` 返回系統全局唯一消息號,避免衝突。

發送端:簡單廣播

public void BroadcastSimple()
{
    var msg = Message.Create((IntPtr)HWND_BROADCAST, (int)MsgId, IntPtr.Zero, IntPtr.Zero);
    MessageWindow.SendMessage(ref msg);
}

接收端:繼承 MessageWindow + 重寫 WndProc

public class MsgListener : MessageWindow
{
    protected override void WndProc(ref Message msg)
    {
        if (msg.Msg == MsgId)
        {
            // 處理消息
            OnMessageReceived();
        }
        base.WndProc(ref msg);
    }

    public event Action MessageReceived;
    private void OnMessageReceived() => MessageReceived?.Invoke();
}

配合 Form 更新 UI (線程安全)

public partial class MainForm : Form
{
    private MsgListener _listener;

    public MainForm()
    {
        InitializeComponent();
        _listener = new MsgListener();
        _listener.MessageReceived += () => 
        {
            if (InvokeRequired)
                Invoke(new Action(UpdateUI));
            else
                UpdateUI();
        };
    }

    private void UpdateUI() { /* 更新控件 */ }
}

進階:WM_COPYDATA 傳遞字符串/對象

標準 `MessageWindow.SendMessage` 不支持 `WM_COPYDATA` (0x004A),需 P/Invoke `SendMessageW` 並手工構造 `COPYDATASTRUCT`。

結構定義與內存管理

[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
    public int dwData;      // 用戶定義數據
    public int cbData;      // 數據字節長度
    public IntPtr lpData;   // 數據指針 (非托管內存)
}

public static class Win32
{
    private const int WM_COPYDATA = 0x004A;
    private const int LMEM_FIXED = 0x0000;
    private const int LMEM_ZEROINIT = 0x0040;
    private const int LPTR = LMEM_FIXED | LMEM_ZEROINIT;

    [DllImport("coredll.dll")] public static extern IntPtr LocalAlloc(int flags, int size);
    [DllImport("coredll.dll")] public static extern IntPtr LocalFree(IntPtr hMem);
    [DllImport("coredll.dll")] public static extern int SendMessageW(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

    public static void SendString(IntPtr hWnd, string text)
    {
        var cds = new COPYDATASTRUCT
        {
            dwData = 1,
            cbData = (text.Length + 1) * 2, // Unicode 字節長度
            lpData = LocalAlloc(LPTR, (text.Length + 1) * 2)
        };
        Marshal.Copy(text.ToCharArray(), 0, cds.lpData, text.Length);

        var lParam = LocalAlloc(LPTR, Marshal.SizeOf(cds));
        Marshal.StructureToPtr(cds, lParam, false);

        SendMessageW(hWnd, WM_COPYDATA, IntPtr.Zero, lParam);

        LocalFree(cds.lpData);
        LocalFree(lParam);
    }
}

發送調用

private void btnSend_Click(object sender, EventArgs e)
{
    Win32.SendString((IntPtr)HWND_BROADCAST, txtInput.Text);
}

接收端解析 WM_COPYDATA

public class MsgListener : MessageWindow
{
    private const int WM_COPYDATA = 0x004A;

    protected override void WndProc(ref Message msg)
    {
        if (msg.Msg == WM_COPYDATA)
        {
            var cds = (COPYDATASTRUCT)Marshal.PtrToStructure(msg.LParam, typeof(COPYDATASTRUCT));
            string text = Marshal.PtrToStringUni(cds.lpData);
            OnDataReceived(text);
        }
        base.WndProc(ref msg);
    }

    public event Action<string> DataReceived;
    private void OnDataReceived(string text) => DataReceived?.Invoke(text);
}

傳遞任意對象 (序列化 + COPYDATA)

// 發送端
byte[] data = SerializeToByteArray(myObject); // BinaryFormatter / Protobuf
// 將 byte[] 按上述方式塞入 COPYDATASTRUCT.lpData 發送

// 接收端
byte[] data = ReadBytesFromPtr(cds.lpData, cds.cbData);
var obj = DeserializeFromByteArray(data);

三種 IPC 方案對比選型

方案優點缺點適用場景
Windows Message輕量、無服務依賴、超低延遲、支持廣播同機器、同會話、數據量小、無持久化進程間輕量通知、UI 同步、單機多進程協作
Point-to-Point Message Queue內核級、優先級、可命名管道CE 支持有限、文檔少實時性要求極高的本地通信
MSMQ離線存轉、事務、跨網絡、可靠投遞需安裝服務、較重、延遲較高斷網環境、異地同步、關鍵業務命令

Windows Message 是「手術刀」,MSMQ 是「運輸車」,按業務體量與可靠性需求選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved