C# 窗口过程消息处理 WndProc
C# 窗口过程消息处理 WndProc
WinForm WndProc
在 WinForm 中一般采用重写 WndProc 的方法对窗口或控件接受到的指定消息进行处理
示例:禁止通过关闭按钮或其他发送 WM_CLOSE 消息的途径关闭窗口
protected override void WndProc(ref Message m)
{
const int WM_CLOSE = 0x0010;
if(m.Msg == WM_CLOSE)
{
// MessageBox.Show("禁止关闭此窗口");
return;
}
base.WndProc(ref m);
}
Control 类中还有个 DefWndProc 为默认的窗口过程
WPF HwndSource
WPF 仅本机窗口或 HwndHost 嵌入控件拥有句柄,可通过 HwndSource 添加消息处理
示例:禁止通过关闭按钮或其他发送 WM_CLOSE 消息的途径关闭窗口
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("禁止关闭此窗口");
handled = true; // 标记为已处理
}
return IntPtr.Zero;
}
WinForm IMessageFilter
注意:1.消息过滤器对于特定线程是唯一的;2.使用消息过滤器可能会降低程序性能
IMessageFilter 接口允许程序在将消息调度到控件或窗口之前捕获消息进行预处理
IMessageFilter 的 PreFilterMessage 与 Control 的 WndProc 接收到的消息是一个交集关系,应用程序接收到的消息来自系统消息队列,相对来说更全,但会有部分消息会直接发送到窗口或控件而不进入系统消息队列
实现 IMessageFilter 接口实例可对整个线程消息循环进行预处理,并根据 m.HWnd 获取消息传入的窗口或控件句柄
示例:截获程序鼠标悬浮消息,窗口标题显示当前悬浮控件名
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; // 过滤消息不继续派发
}
return false; // 允许消息派发到下一个过滤器或控件
}
}
WinForm NativeWindow
NativeWindow 是 IWin32Window 的低级封装,并且和 WinForm Control 一样拥有 WndProc 和 DefWndProc 方法,故同样可通过重写 WndProc 方法处理消息
可以通过 CreateHandle(new CreateParams()) 创建没有 UI 的仅消息循环的窗口。比如托盘图标类 NotifyIcon 内部会创建一个 NativeWindow 用来接收任务栏创建消息 WM_TASKBARCREATED ("TaskbarCreated"),在资源管理器崩溃重启后重新创建图标。
附加到其他窗口
由于 WinForm Control WndProc 是密封的,处理消息时必须继承类型并重写,需要单独进行消息处理的窗口或控件较多时,对原代码具有很大的侵入性;而 IMessageFilter 是针对整个应用程序的消息循环,官方文档说使用消息过滤器很可能会降低程序性能;相对来说,由于 HwndSource AddHook 和 RemoveHook 不是密封的,WPF 程序可以在不侵入原代码的条件下处理窗口消息,在可复用性上面反而还具有优势。但如果仔细看看 NativeWindow 源代码,会发现它内部调用了 SetWindowLong GWL_WNDPROC (窗口子类化),可以通过 AssignHandle 附加到任意窗口或控件进行消息处理,这个窗口不限制类型,甚至可以附加到其他程序窗口。
这里提供一个静态辅助类,借助 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">消息处理过程移除回调</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);
}
}
}
}
C# 窗口过程消息处理 WndProc的更多相关文章
- 窗口过程 Wndproc
操作系统向应用程序发送一系列消息,如左键按下和左键抬起,应用程序将通过GetMessage等方法 Wndproc应用例子最终将消息提交到窗口过程(WndProc)指向一个应用程序定义的窗口过程的指针. ...
- win32编程中消息循环和WndProc()窗口过程函数
原文地址:https://blog.csdn.net/zxxSsdsd/article/details/45504383 在win32程序的消息循环函数中 while (GetMessage (&a ...
- MSG结构体和WndProc窗口过程详解
MSG结构体和WndProc窗口过程对于Windows编程非常重要,如果不了解它们,可以说就没有学会Windows编程. MSG结构体 MSG 结构体用来表示一条消息,各个字段的含义如下: typed ...
- ATL中窗口句柄与窗口过程的关联方法
ATL中采用了一种动态生成机器指令的方式进行窗口句柄与窗口对象进行关联,以是详细分析: CWindowImpl会在第一次调用Create时注册窗口类,该窗口类是的信息是在CWindowImpl的子类中 ...
- 深入解析Windows窗口创建和消息分发(三个核心问题:怎么将不同的窗口过程勾到一起,将不同的hwnd消息分发给对应的CWnd类去处理,CWnd如何简单有效的去处理消息,由浅入深,非常清楚) good
笔记:争取不用看下面的内容,只看自己的笔记,就能记住这个流程,就算明白了: _tWinMain-->AfxWinMain,它调用四个函数: -->AfxWinInit用于做一些框架的初始化 ...
- win32程序通过LPCREATESTRUCT中的lpCreateParams传递参数给窗口过程函数
win32窗口程序中如果需要给窗口过程函数传递自定义参数,可以通过LPCREATESTRUCT结构体中的lpCreateParams进行传递. 创建窗口实例函数: m_hWnd = CreateWin ...
- C#调用WinAPI及窗口过程
C#调用WINAPI及Windows窗口消息的发与送 最近在做一个餐饮项目(C#Winform),其中有一块是做点菜宝接口的对接,点菜宝的厂商提供了一个WX.exe的驱动程序,这个驱动程序无直接打开, ...
- 从普通函数到对象方法 ------Windows窗口过程的面向对象封装
原文地址:http://blog.csdn.net/linzhengqun/article/details/1451088 从普通函数到对象方法 ------Windows窗口过程的面向对象封装 开始 ...
- windows窗口过程函数名词解析
windows窗口过程函数名词解析 LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) 1. LR ...
- 窗口过程 - Windows程序设计(SDK)006
窗口过程 让编程改变世界 Change the world by program 内容节选: Windows 把这样一个窗口分为了客户区和非客户区,这里边白色的这一大片就是客户区,而这些标题栏.菜单栏 ...
随机推荐
- JVM中线程的状态以及状态间的转换
线程在一定条件下,状态会发生变化.线程一共有以下几种状态: 新建状态(New):新创建了一个线程对象. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的 ...
- JS播放m3u8
JS播放m3u8: 利用 hls.min.js <!DOCTYPE html> <html> <head> <title>HLS Video Playb ...
- Ps cs4 -把GIF背景变透明-简单操作,还可以将视频转换GIF
准备软件: 1.Ps cs4 2.QuickTime Player 7.74 开始: 1. 2.弹出文件选择框,但是发现不能选择GIF格式. 3.没关系,在文件名框输入*.*回车,就发现可以选择GIF ...
- w3cschool-微信小程序开发文档-API
https://www.w3cschool.cn/weixinapp/weixinapp-network-request.html 微信小程序API 发起请求 发起 HTTPS 网络请求.使用前请注意 ...
- 修改Maven仓库到国内
修改Maven仓库到国内 Maven home directory:选择已安装的Maven目录. User settings file:根据安装Maven自动显示的配置文件settings.xml路径 ...
- code-generate(一个通用的代码生成工具)开源项目介绍
code-generate是一个通用的代码生成工具,支持从各种元数据,通过定义模板生成需要的代码,减少低级重复的编码工作.目前支持通过数据库元数据生成业务对象.数据访问对象等. 项目地址 gitee: ...
- 安全、高效!天翼云HPFS助企业一臂之力!
近年来,随着各行业数智转型逐步深入以及人工智能大模型的蓬勃发展,气象分析.大模型训练.自动驾驶.石油勘探.EDA仿真.基因分析等高性能计算(HPC)场景和智算场景(AI)不仅对算力需求激增,也产生了图 ...
- linux goreplay流量压测工具
项目地址https://github.com/buger/goreplay 下载wget https://github.com/buger/goreplay/releases/download/v0. ...
- Clickhouse常见异常
一.异常 1)DB::Exception: Nested type Array(String) cannot be inside Nullable type (version 20.4.6.53 (o ...
- Luogu P1930 亚瑟王的宫殿 题解 [ 蓝 ] [ 分层图最短路 ] [ 枚举 ]
亚瑟王的宫殿:比较 tricky 的图论. 图论做法 思路 因为是无向图,所以考虑一个经典 trick,把所有点到集合点的距离之和化为集合点到其他所有点的位置之和,就可以从集合点做单源最短路了. 于是 ...