所谓的子类化,网上有很多说明,我就说我个人的随意理解,可能有误,请列位看官斟酌理解。

所谓子类化,个人理解就是拦截某个控件的消息以及样式来进行自己的特定处理以达到特殊的功能需求。这个子类化,可以有子类化别人的程序的控件,也有子类化自己程序的控件。

子类化别人的,就需要注入到别人的程序内部,然后做对应处理拦截,我这里主要针对的是自己程序的处理。

这个就比较简单了,有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的子类化控件消息, 消息子类化相关推荐

  1. 详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息

    Windows消息的分类 1. 标准消息(队列消息)   除WM_COMMAND之外,所有以WM_开头的消息都是标准消息,如WM_MOUSEMOVE.WM_LBUTTONUP.WM_KEYDOWN.W ...

  2. 【转】详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息

    转自:http://blog.sina.com.cn/s/blog_4b3c1f950100nten.html Windows消息的分类 1. 标准消息(队列消息)   除WM_COMMAND之外,所 ...

  3. 主窗口给按钮控件发送消息 BN_CLICKED和BN_SETFOCUS和BN_KILLFOUCS

    先说明一下,按钮控件的消息有很多种,下面的列表是按钮发送的消息,其中用的比较多是BN_CLICKED和BN_SETFOCUS和BN_KILLFOUCS /** User Button Notifica ...

  4. 设置QWidget及其子类控件背景颜色

    QWidget是所有用户界面控件的基类,所以用同样的方法为其子类控件改变背景颜色. Qt中窗口背景的设置,下面介绍三种方法. 使用QPalette 使用Style Sheet 绘图事件使用Style ...

  5. 【第3版emWin教程】第49章 emWin6.x的AppWizard创建控件回调消息

    教程不断更新中:第3版emWin教程和ThreadX GUIX教程开工,双管齐下,GUIX更新至第28章,emWin更新至第50章(2021-10-01) - uCOS & uCGUI &am ...

  6. 动态顺序图可视化控件

    目录 介绍 为什么要使用它? 分布式系统的端到端跟踪 调试器 背景 使用代码 示例 如何使用控件 怎么运行的 Tick()方法 元素渲染 API引用 顺序 参加者 消息 激活 方框 SequenceD ...

  7. 几百个Android开源个性化控件、工具库、项目、开发工具快快收藏

    场景 如果之前是学过Java的,那么Android将很好上手. 新手入门,往往不会利用已经开源并实现效果的个性化控件和工具库等. 比如像下面这些控件效果 又比如一些工具库,包括依赖注入框架.图片缓存. ...

  8. Delphi XE2 新控件 布局Panel TGridPanel TFlowPanel

    Delphi XE2 新控件 Firemonkey 布局Panel Windows平台VCl TGridPanel TFlowPanel FMX 跨平台 TLayout TGridLayout TFl ...

  9. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

最新文章

  1. php怎么添加框架,PHPWind 给默认的风格添加大框架
  2. eclipse——jsp字体设置
  3. iframe子页面与父页面元素的访问以及js变量的访问[zhuan]
  4. 关于储存设备知识介绍汇总
  5. ajax返回数据类型为JSON数据的处理
  6. 为什么鞋带总是松开?罪魁祸首其实是…
  7. java将dxf展示在网页_七天串起java技术栈-第四天
  8. java 并行_Java 中不同的并行实现的性能比较
  9. 计网期末复习 - CRC循环冗余校验计算
  10. css 查看更多_Cirrus(原型制作CSS框架)下载-Cirrus(原型制作CSS框架)v0.6.0免费版下载...
  11. text 热敏打印机_C# 热敏打印机 Socket 网络链接 打印 图片 (一)
  12. python爬虫的意义_爬虫的意义与爬虫基本流程
  13. Tableau中使用R语言做----k-means聚类图像
  14. Java网络象棋游戏(功能版)
  15. 阿里云亮眼财报背后,云的打开方式正在重塑
  16. ANSI E1.11-2008(R2018) DMX512-A 部分翻译
  17. 数据结构查找-7-3 词频统计 (30 分)
  18. ibaanalyzer使用教程_ibaanalyzer中文手册
  19. Cisco实验-配置Cisco交换机
  20. 卷积的意义(幽默解释)--转

热门文章

  1. 【恋上数据结构】希尔排序
  2. python安装pip之后 pip命令报错解决方法
  3. 白皮书 | 以太坊 (Ethereum ):下一代智能合约和去中心化应用平台
  4. js休眠实现sleep[博]
  5. 东航期货模拟交易brockerid(期货公司的客户号)
  6. prod和probor在matlab,matlab补充教程分析.ppt
  7. 前阿里财务人告诉你:抛弃Excel,原来报表竟然还能这么快
  8. 想转行数据分析,看完这篇再做决定
  9. vue3中setup()函数的使用一
  10. linux mysql 5.0.45_linux 下安装mysql-5.0.45.tar.gz