Delphi的子类化控件消息, 消息子类化
所谓的子类化,网上有很多说明,我就说我个人的随意理解,可能有误,请列位看官斟酌理解。
所谓子类化,个人理解就是拦截某个控件的消息以及样式,来进行自己的特定处理以达到特殊的功能需求。这个子类化,可以有子类化别人的程序的控件,也有子类化自己程序的控件。
子类化别人的,就需要注入到别人的程序内部,然后做对应处理拦截,我这里主要针对的是自己程序的处理。
这个就比较简单了,有API函数SetWindowLong,用这个函数,就可以拦截某WinControl的Wndproc窗口过程了。
在Delphi中,所有的消息处理,实际上都是用Application来代理处理以及转发派遣的,
所以,不必要SetWindowLong,就可以拦截所有控件的消息,Application.OnMessage中处理就可以,比较容易,
不过,这个消息事件中有个比较蛋疼的,就是控件的释放消息WM_Destroy,里面捕捉不到。
所以,可以考虑到用SetWindowLong替换掉窗口过程,在这个新窗口过程中处理这消息。
替换的方式是
SetWindowLong(ControlHandle,GWL_WNDPROC,newProc);
这个newProc过程是
function NewWndProc(hwnd: THandle;msg: UINT;wparam: wParam;lParam: LParam);integer;stdcall;
就可以这样
function NewWndProc(hwnd: THandle;msg: UINT;wparam: wParam;lParam: LParam);integer;stdcall;beginend;
然后
SetWindowLong(ControlHandle,GWL_Wndproc,LongInt(@NewWndproc));
但是这样处理,就是一个全局函数,如果要通用,就要专门定义一个全局变量,用来代理处理
我这里说的一种方式,就是直接在一个类当中来处理,我想这样说,应该很多人都会说,很容易了,
Delphi自带的有一个函数MakeObjectInstance,用这个函数,就可以将这个窗口函数定义到类内部来使用,
对应方式就是
typeTTest = classprivateFP,OldP: Pointer;procedure NewProc(var msg: TMessage);publicconstructor Create; destructor Destroy;procedure HookWNdproc(hwnd: THandle);end;constructor TTest.Create; beginFp := MakeObjectInstance(NewProc); end;destructor Destroy;override; beginFreeObjectInstance(Fp );inherited; end;procedure TTest.HookWNdproc(hwnd: THandle); beginOldP := Pointer(SetWindowLong(hwnd,GWL_Wndproc,Fp)); end;
这里,应该明白的人,就已经知道了,NewProc过程中,没有控件的句柄传递过来,这个就是Delphi处理过了,目的是无句柄的消息派遣传递,也可以用这个来处理的。
中间的问题就出在MakeObjectInstance这个函数中,本函数的内容,可以自行去Delphi中看,我就不弄上来了。
函数的目的是将控件的窗口过程Hook导向了Delphi的一个内部处理函数StdProc,这个函数在Classes单元中,是上面声明的标准的窗口过程函数
function NewWndProc(hwnd: THandle;msg: UINT;wparam: wParam;lParam: LParam);integer;stdcall;
那么我们就可以知道,实际上NewProc实际上调用的还是StdProc这个函数,那么既然如此,那么就肯定还是能够获得里面传递过来的参数的。那么这里就涉及到了程序的函数调用的一个原理,这个东西,实际上在汇编课程中,应该会讲到,就算不讲,自己反一下Delphi的源码就可以看出来,函数调用初期,进入函数的时候,都会有对应的
push ebp mov ebp,esp
这样的语句,这个Push ebp目的就是压入上一次的函数环境的堆栈,以便于函数调用完成之后,能够顺利返回,所以,从这里,我们就可以知道上一次函数的调用堆栈在ebp中,而上一个函数就是function NewWndProc(hwnd: THandle;msg: UINT;wparam: wParam;lParam: LParam);integer;stdcall;这个函数了,那么知道了他的调用堆栈,获取堆栈中的参数就很容易了咯,可以来看NewWndProc的堆栈情况,
Windows的Stdcall回调函数的参数传递方式是从从右往左进栈,参数压栈之后还会压入一个现场,所以可以知道Hwnd的参数就在这个现场后面,
那么就可以知道,这个Hwnd的值了
代码如下:
procedure TTest.NewProc(var msg: TMessage); varcontrolHandle: THandle; beginasmmov edx,[ebp] //stdproc个函数的堆栈顶mov edx,[edx+8] //Hwnd参数,参数之后压入了一个现场,所以+8end; end;
那么这里就可以用
typeTTest = classprivateFP,OldP: Pointer;procedure NewProc(var msg: TMessage);publicconstructor Create; destructor Destroy;procedure HookWNdproc(hwnd: THandle);end;procedure TTest.NewProc(var msg: TMessage); varControlHandle: THandle; beginasmmov edx,[ebp]mov edx,[edx+8]mov controlHandle,edxend;//通过ControlHandle来判定控件,做通用处理 end;constructor TTest.Create; beginFp := MakeObjectInstance(NewProc); end;destructor Destroy;override; beginFreeObjectInstance(Fp );inherited; end;procedure TTest.HookWNdproc(hwnd: THandle); beginOldP := Pointer(SetWindowLong(hwnd,GWL_Wndproc,Fp)); end;
于是,这个淫荡的法则,完成了。
转载于:https://www.cnblogs.com/yzryc/p/6404948.html
Delphi的子类化控件消息, 消息子类化相关推荐
- 详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息
Windows消息的分类 1. 标准消息(队列消息) 除WM_COMMAND之外,所有以WM_开头的消息都是标准消息,如WM_MOUSEMOVE.WM_LBUTTONUP.WM_KEYDOWN.W ...
- 【转】详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息
转自:http://blog.sina.com.cn/s/blog_4b3c1f950100nten.html Windows消息的分类 1. 标准消息(队列消息) 除WM_COMMAND之外,所 ...
- 主窗口给按钮控件发送消息 BN_CLICKED和BN_SETFOCUS和BN_KILLFOUCS
先说明一下,按钮控件的消息有很多种,下面的列表是按钮发送的消息,其中用的比较多是BN_CLICKED和BN_SETFOCUS和BN_KILLFOUCS /** User Button Notifica ...
- 设置QWidget及其子类控件背景颜色
QWidget是所有用户界面控件的基类,所以用同样的方法为其子类控件改变背景颜色. Qt中窗口背景的设置,下面介绍三种方法. 使用QPalette 使用Style Sheet 绘图事件使用Style ...
- 【第3版emWin教程】第49章 emWin6.x的AppWizard创建控件回调消息
教程不断更新中:第3版emWin教程和ThreadX GUIX教程开工,双管齐下,GUIX更新至第28章,emWin更新至第50章(2021-10-01) - uCOS & uCGUI &am ...
- 动态顺序图可视化控件
目录 介绍 为什么要使用它? 分布式系统的端到端跟踪 调试器 背景 使用代码 示例 如何使用控件 怎么运行的 Tick()方法 元素渲染 API引用 顺序 参加者 消息 激活 方框 SequenceD ...
- 几百个Android开源个性化控件、工具库、项目、开发工具快快收藏
场景 如果之前是学过Java的,那么Android将很好上手. 新手入门,往往不会利用已经开源并实现效果的个性化控件和工具库等. 比如像下面这些控件效果 又比如一些工具库,包括依赖注入框架.图片缓存. ...
- Delphi XE2 新控件 布局Panel TGridPanel TFlowPanel
Delphi XE2 新控件 Firemonkey 布局Panel Windows平台VCl TGridPanel TFlowPanel FMX 跨平台 TLayout TGridLayout TFl ...
- Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类
概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...
最新文章
- php怎么添加框架,PHPWind 给默认的风格添加大框架
- eclipse——jsp字体设置
- iframe子页面与父页面元素的访问以及js变量的访问[zhuan]
- 关于储存设备知识介绍汇总
- ajax返回数据类型为JSON数据的处理
- 为什么鞋带总是松开?罪魁祸首其实是…
- java将dxf展示在网页_七天串起java技术栈-第四天
- java 并行_Java 中不同的并行实现的性能比较
- 计网期末复习 - CRC循环冗余校验计算
- css 查看更多_Cirrus(原型制作CSS框架)下载-Cirrus(原型制作CSS框架)v0.6.0免费版下载...
- text 热敏打印机_C# 热敏打印机 Socket 网络链接 打印 图片 (一)
- python爬虫的意义_爬虫的意义与爬虫基本流程
- Tableau中使用R语言做----k-means聚类图像
- Java网络象棋游戏(功能版)
- 阿里云亮眼财报背后,云的打开方式正在重塑
- ANSI E1.11-2008(R2018) DMX512-A 部分翻译
- 数据结构查找-7-3 词频统计 (30 分)
- ibaanalyzer使用教程_ibaanalyzer中文手册
- Cisco实验-配置Cisco交换机
- 卷积的意义(幽默解释)--转
热门文章
- 【恋上数据结构】希尔排序
- python安装pip之后 pip命令报错解决方法
- 白皮书 | 以太坊 (Ethereum ):下一代智能合约和去中心化应用平台
- js休眠实现sleep[博]
- 东航期货模拟交易brockerid(期货公司的客户号)
- prod和probor在matlab,matlab补充教程分析.ppt
- 前阿里财务人告诉你:抛弃Excel,原来报表竟然还能这么快
- 想转行数据分析,看完这篇再做决定
- vue3中setup()函数的使用一
- linux mysql 5.0.45_linux 下安装mysql-5.0.45.tar.gz