核心 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 處理控制代碼與參數