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

C# 視窗訊息機制實戰:P/Invoke SendMessage 與 DefWndProc 覆寫

     編輯:關於C語言

核心 API 宣告

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class Win32Messaging {
    [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", EntryPoint = "PostMessage", CharSet = CharSet.Auto)]
    public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
}

自訂訊息常數

public static class CustomMessages {
    public const int WM_USER = 0x0400;
    public const int WM_APP = 0x8000;
    
    // 應用程式自訂訊息建議使用 WM_APP 範圍避免衝突
    public const int MY_CUSTOM_MSG = WM_APP + 1;
    public const int ANOTHER_MSG = WM_APP + 2;
}

發送訊息

public void SendCustomMessage(string targetWindowTitle, uint msg, IntPtr wParam, IntPtr lParam) {
    IntPtr hWnd = Win32Messaging.FindWindow(null, targetWindowTitle);
    if (hWnd == IntPtr.Zero)
        throw new Exception($"找不到視窗: {targetWindowTitle}");
    
    Win32Messaging.SendMessage(hWnd, msg, wParam, lParam);
    // 或非同步:PostMessage(hWnd, msg, wParam, lParam);
}

接收訊息:覆寫 DefWndProc

public class MessageReceiverForm : Form {
    protected override void DefWndProc(ref Message m) {
        switch ((uint)m.Msg) {
            case CustomMessages.MY_CUSTOM_MSG:
                // m.WParam, m.LParam 為傳入參數
                string info = $"收到自訂訊息: WParam={m.WParam}, LParam={m.LParam}";
                MessageBox.Show(info);
                break;
                
            case CustomMessages.ANOTHER_MSG:
                // 處理其他訊息
                break;
                
            default:
                // 必須呼叫基底實作處理標準訊息
                base.DefWndProc(ref m);
                break;
        }
    }
}

完整範例:兩個 Form 互傳訊息

發送端

public class SenderForm : Form {
    private Button btnSend;
    
    public SenderForm() {
        btnSend = new Button { Text = "發送訊息給接收端", Dock = DockStyle.Fill };
        btnSend.Click += (s, e) => {
            try {
                Win32Messaging.SendMessage(
                    Win32Messaging.FindWindow(null, "ReceiverForm"),
                    CustomMessages.MY_CUSTOM_MSG,
                    (IntPtr)123, (IntPtr)456);
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        };
        Controls.Add(btnSend);
    }
}

接收端

public class ReceiverForm : Form {
    protected override void DefWndProc(ref Message m) {
        if ((uint)m.Msg == CustomMessages.MY_CUSTOM_MSG) {
            string txt = $"WParam: {m.WParam.ToInt32()}, LParam: {m.LParam.ToInt32()}";
            MessageBox.Show(txt, "收到自訂訊息");
        } else {
            base.DefWndProc(ref m);
        }
    }
}

進階主題

結構體參數封送

[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT {
    public IntPtr dwData;
    public int cbData;
    public IntPtr lpData;
}

public void SendStringData(IntPtr hWnd, string text) {
    byte[] data = System.Text.Encoding.Unicode.GetBytes(text + "\0");
    GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
    try {
        COPYDATASTRUCT cds = new COPYDATASTRUCT {
            dwData = IntPtr.Zero,
            cbData = data.Length,
            lpData = handle.AddrOfPinnedObject()
        };
        IntPtr lParam = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
        Marshal.StructureToPtr(cds, lParam, false);
        SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, lParam);
    } finally {
        handle.Free();
    }
}

訊息過濾器

public class MyMessageFilter : IMessageFilter {
    public bool PreFilterMessage(ref Message m) {
        if ((uint)m.Msg == CustomMessages.MY_CUSTOM_MSG) {
            // 全域攔截處理
            return true;  // 表示已處理,不再分派
        }
        return false;
    }
}

// 註冊:Application.AddMessageFilter(new MyMessageFilter());

注意事項

  • WM_USER (0x0400-0x7FFF):私有視窗類別用,跨進程易衝突
  • WM_APP (0x8000-0xBFFF):應用程式全域用,建議自訂訊息用此範圍
  • RegisterWindowMessage:唯一字串產生全域唯一訊息 ID,最安全
  • SendMessage 同步阻塞:接收端處理未返回前發送端卡住;PostMessage 非同步
  • 64 位元相容:使用 IntPtr 而非 int 處理控制代碼與參數
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved