C#?窗口過程消息處理?WndProc的方法詳解
WinForm WndProc
在 WinForm 中一般采用重寫 WndProc 的方法對窗口或控件接受到的指定消息進行處理
示例:禁止通過關(guān)閉按鈕或其他發(fā)送 WM_CLOSE 消息的途徑關(guān)閉窗口
protected override void WndProc(ref Message m)
{
const int WM_CLOSE = 0x0010;
if(m.Msg == WM_CLOSE)
{
// MessageBox.Show("禁止關(guān)閉此窗口");
return;
}
base.WndProc(ref m);
}Control 類中還有個 DefWndProc 為默認(rèn)的窗口過程
WPF HwndSource
WPF 僅本機窗口或 HwndHost 嵌入控件擁有句柄,可通過 HwndSource 添加消息處理
示例:禁止通過關(guān)閉按鈕或其他發(fā)送 WM_CLOSE 消息的途徑關(guān)閉窗口
HwndSource source = null;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr handle = new WindowInteropHelper(this).Handle;
source = HwndSource.FromHandle(handle);
source.AddHook(WndProc);
}
protected override void OnClosed(EventArgs e)
{
source?.RemoveHook(WndProc);
base.OnClosed(e);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_CLOSE = 0x0010;
if(msg == WM_CLOSE)
{
// MessageBox.Show("禁止關(guān)閉此窗口");
handled = true; // 標(biāo)記為已處理
}
return IntPtr.Zero;
}WinForm IMessageFilter
? 注意:1.消息過濾器對于特定線程是唯一的;2.使用消息過濾器可能會降低程序性能
IMessageFilter 接口允許程序在將消息調(diào)度到控件或窗口之前捕獲消息進行預(yù)處理
IMessageFilter 的 PreFilterMessage 與 Control 的 WndProc 接收到的消息是一個交集關(guān)系,應(yīng)用程序接收到的消息來自系統(tǒng)消息隊列,相對來說更全,但會有部分消息會直接發(fā)送到窗口或控件而不進入系統(tǒng)消息隊列
實現(xiàn) IMessageFilter 接口實例可對整個線程消息循環(huán)進行預(yù)處理,并根據(jù) m.HWnd 獲取消息傳入的窗口或控件句柄
示例:截獲程序鼠標(biāo)懸浮消息,窗口標(biāo)題顯示當(dāng)前懸浮控件名
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var filter = new SampleMsgFilter();
Application.AddMessageFilter(filter); // 添加到消息泵
Application.Run(new MainForm());
Application.RemoveMessageFilter(filter); // 從消息泵移除
}
}
sealed class SampleMsgFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
const int WM_MOUSEHOVER = 0x02A1;
if(m.Msg == WM_MOUSEHOVER && Control.FromHandle(m.HWnd) is Control ctr)
{
ctr.FindForm().Text = ctr.Name;
return true; // 過濾消息不繼續(xù)派發(fā)
}
return false; // 允許消息派發(fā)到下一個過濾器或控件
}
}WinForm NativeWindow
NativeWindow 是 IWin32Window 的低級封裝,并且和 WinForm Control 一樣擁有 WndProc 和 DefWndProc 方法,故同樣可通過重寫 WndProc 方法處理消息
可以通過 CreateHandle(new CreateParams()) 創(chuàng)建沒有 UI 的僅消息循環(huán)的窗口。比如托盤圖標(biāo)類 NotifyIcon 內(nèi)部會創(chuàng)建一個 NativeWindow 用來接收任務(wù)欄創(chuàng)建消息 WM_TASKBARCREATED ("TaskbarCreated"),在資源管理器崩潰重啟后重新創(chuàng)建圖標(biāo)。
附加到其他窗口
由于 WinForm Control WndProc 是密封的,處理消息時必須繼承類型并重寫,需要單獨進行消息處理的窗口或控件較多時,對原代碼具有很大的侵入性;而 IMessageFilter 是針對整個應(yīng)用程序的消息循環(huán),官方文檔說使用消息過濾器很可能會降低程序性能;相對來說,由于 HwndSource AddHook 和 RemoveHook 不是密封的,WPF 程序可以在不侵入原代碼的條件下處理窗口消息,在可復(fù)用性上面反而還具有優(yōu)勢。但如果仔細看看 NativeWindow 源代碼,會發(fā)現(xiàn)它內(nèi)部調(diào)用了 SetWindowLong GWL_WNDPROC (窗口子類化),可以通過 AssignHandle 附加到任意窗口或控件進行消息處理,這個窗口不限制類型,甚至可以附加到其他程序窗口。
這里提供一個靜態(tài)輔助類,借助 NativeWindow 簡化附加窗口消息過程處理操作:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Wondershare.WinTool.Helpers
{
public delegate bool HookProc(ref Message m);
public static class MessageHooker
{
sealed class HookWindow : NativeWindow
{
List<KeyValuePair<HookProc, Action>> hooks;
public HookWindow(IntPtr hWnd)
{
AssignHandle(hWnd);
}
public void AddHookProc(HookProc hook, Action removedHandler)
{
if (hooks == null)
{
hooks = new List<KeyValuePair<HookProc, Action>>();
}
hooks.Insert(0, new KeyValuePair<HookProc, Action>(hook, removedHandler));
}
public void RemoveHookProc(HookProc hook)
{
if (hooks != null)
{
for (int i = hooks.Count - 1; i >= 0; i--)
{
if (hooks[i].Key == hook)
{
hooks[i].Value?.Invoke();
hooks.RemoveAt(i);
}
}
}
}
protected override void WndProc(ref Message m)
{
if (hooks != null)
{
foreach (var hook in hooks)
{
if (hook.Key(ref m)) return;
}
const int WM_NCDESTORY = 0x0082;
if (m.Msg == WM_NCDESTROY) // 窗口銷毀時移除所有 hook
{
for (int i = hooks.Count - 1; i >= 0; i--)
{
hooks[i].Value?.Invoke();
}
hooks = null;
}
base.WndProc(ref m);
}
}
}
/// <summary>附加消息處理過程到窗口</summary>
/// <param name="handle">需要附加消息處理過程的窗口句柄</param>
/// <param name="hook">消息處理過程</param>
/// <param name="removedHandler">消息處理過程移除回調(diào)</param>
public static void AddHook(IntPtr handle, HookProc hook, Action removedHandler = null)
{
if (!(NativeWindow.FromHandle(handle) is HookWindow window))
{
window = new HookWindow(handle);
}
window.AddHookProc(hook, removedHandler);
}
/// <summary>從窗口移除附加的消息處理過程</summary>
/// <param name="handle">需要移除消息處理過程的窗口句柄</param>
/// <param name="hook">消息處理過程</param>
public static void RemoveHook(IntPtr handle, HookProc hook)
{
if (NativeWindow.FromHandle(handle) is HookWindow window)
{
window.RemoveHookProc(hook);
}
}
}
}到此這篇關(guān)于C# 窗口過程消息處理 WndProc的方法詳解的文章就介紹到這了,更多相關(guān)C# 消息處理 WndProc內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# StreamReader類實現(xiàn)讀取文件的方法
這篇文章主要介紹了C# StreamReader類實現(xiàn)讀取文件的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
C#使用CryptoStream類加密和解密字符串的實現(xiàn)
CryptoStream設(shè)計用于在內(nèi)容以流的形式輸出到文件時加密和解密內(nèi)容,本文主要介紹了C#使用CryptoStream類加密和解密字符串的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-01-01

