VCL定义和使用CM_Message的原因(主要是内部控制,同时可简化参数传递,还可截住消息,统一走消息路线,还可省内存)
内部控制是指,做了某些操作后产生某些效果,但是Windows系统本身不提供这样的消息,应此不得不自定义。比如父窗口改变了字体,那么所有子窗口也都应该改变字体,至少也得通知一下它们,让子控件自己决定是否响应以及怎么响应(替代了虚函数的作用,但是消息更加干净利落,愿不愿意以及怎么做完全由对方决定),但是Windows不提供这样的消息,于是自定义消息CM_PARENTFONTCHANGED闪亮登场。VCL当然也可以定义一个函数,然后直接去执行这个函数达到目的,但是参数的个数以及类型就成了问题,处理函数的时机的灵活性就成了问题,等等,而使用消息的话,这些问题都不存在,并且还有利于不同VCL版本的兼容(比如换个消息对应的函数名)。此外,需要强调的是,这些消息并不是SendMessage发送的,大多数仍是Perform执行的(需要稍加统计进行确认),因此实际上这些”消息“并没有经过Windows系统进行中转处理,而是会被直接执行,因此不会造成执行时的延迟。
-----------------------------------------------------------------
问题:最近看VCL源码,看到经常需要发送CM_消息去调用某个函数,我就不明白,为什么要这样。直接调用函数名称不是挺好吗,尤其是调用虚函数的话,一样很灵活。而且发消息还有个缺点,更依赖于系统,如果系统正忙怎么办?而虚函数只和语言自己有关系,不是更稳妥可靠吗?为什么要自定义消息呢?还把VCL框架搞的更复杂了。
比如:
procedure TWinControl.SetBorderWidth(Value: TBorderWidth);
begin
if FBorderWidth <> Value then
begin
FBorderWidth := Value;
Perform(CM_BORDERCHANGED, 0, 0); // 这里直接调用函数名称不好吗?
end;
end;
procedure TWinControl.CMBorderChanged(var Message: TMessage);
begin
inherited;
if HandleAllocated then
begin
SetWindowPos(Handle, 0, 0,0,0,0, SWP_NOACTIVATE or
SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED);
if Visible then
Invalidate;
end;
end;
----------------------------------------------------------------
回答:
1. Perform是直接调用WindowProc函数,同步调用没有系统忙不忙之说。相当于SendMessage。不发消息直接调用函数倒也行,不过系统的消息处理总是要处理的。不如就统一走消息这条路了。
2. 最主要是参数的简洁,Perform函数会把三个参数重新组织成一个消息,然后发给其它函数的时候TMessage就可以作为一个整体发给别的函数了,这样还方便写消息索引函数,虚函数与消息的对应没有消息索引函数来的明显。根据传来的三个参数来构建一个消息,这也许是使用CM的关键原因。否则:
1)每个虚函数都需要三个参数写起来还不烦死,看起来烦,写起来也烦(函数参数的简洁)。
2)即使可以传递三个参数给虚函数,虽然可以,但是不够通用,发消息的话只要对应消息索引即可,后两个参数被内包含了,这样不必仅仅为lparam和wparam的不同写上多个不同的虚函数。不如就统一走消息这条路了(函数个数的简洁)。
3)或者想节省函数的参数个数,并直接调用消息处理函数也是一样的效果,这样的话每个发送方都组装一遍也很烦,这样代码就重复了,这里可以统一使用Perform可避免重复组装的问题,这样代码显得相当地简洁(VCL库代码的简洁)。
3. 发消息还可以在WndProc里截住并单独处理,不必单独写成函数,虚函数不行,只能单独写(函数个数的简洁,使用时候的简洁)。
4. 另外消息函数实际是动态函数,如果子类派生层次比较多的话比虚函数在内存上是要节省一些的。而用法和虚函数又差不多。当然,在Delphi下虚函数也可使用dynamic达到与消息索引函数相同的效果。但是无论如何,消息函数恰好也是节省内存的,那就更有理由使用了(内存的简洁)。
总结:
因参数个数的原因,统一走消息路线,好像是很正确的理解。
----------------------------------------------------------------
不是理由的理由:
消息可以跨进程,虚函数能吗
----------------------------------------------------------------
进一步提问:
都说的在理。不过为啥要统一走消息啊,自定义消息累不累啊,而且我看有些地方也是调用虚函数的,也不在少数。不过Borland有意搞这个自定义消息,应该还是别有用意?能不能挖空心思再想想啊。另外,我有空把它全部改成虚函数试试,看看编出来的程序还会正确执行不?这不失为一次对OO深刻理解的尝试。
回答:
有没有深意看其它VCL源码,打开VCL所有源码,可以看到CM消息的所有使用情况。不过上面应该已经猜得八九不离十。
----------------------------------------------------------------
参考:
http://bbs.csdn.net/topics/390888872
-----------------------------------------------------------------
有些可能是为了整个vcl的速度
用虚函数方法会增加vmt的长度,减慢vcl的速度
其实估计是参数构造原因,以及减小内存的原因。
你知道,消息只要有句柄就能发过去
想对使用环境,更减少耦合,
比如一个控件,我只知道句柄,我要执行它的方法
那只能用消息传递,
VCL定义和使用CM_Message的原因(主要是内部控制,同时可简化参数传递,还可截住消息,统一走消息路线,还可省内存)的更多相关文章
- windows消息值全部定义,从消息值得到消息名称(系统消息定义从0到1023,从1024开始就是WM_USER,但是中间有325个WM_undefined消息,估计是备用,另外各控件都有一些reserved消息,也是为了备用)LostSpeed
前言 在逆向算法扫描插件时, 遇到一个windows消息值在msdn中没有定义. 去查资料, 有个老外将全部windows消息值和消息名称定义都码好了:) 写个测试程序, 封装了一个接口, 从消息值得 ...
- C++基类的析构函数定义为虚函数的原因
1:每个析构函数只会清理自己的成员(成员函数前没有virtual).2:可能是基类的指针指向派生类的对象,当析构一个指向派生类的成员的基类指针,这时程序不知道这么办,可能会造成内存的泄露,因此此时基类 ...
- ZStack深度试用:部署、架构与网络及其与OpenStack的对比
摘要:本文是开源IaaS软件ZStack的深度试用报告,分别从部署.架构和网络三个层面分享作者的试用体验,并与OpenStack进行简单的对比,文章最后也对ZStack的改进方向提出了自己的思考.(转 ...
- 就这么漂来漂去---一个毕业三个月的java程序员的裸辞风波
注:这并不是一篇技术文章,而是记录了我这几个月经历的入职,裸辞,找工作的心路历程,简单介绍一个博主的情况,我是16年毕业生,校招进了一家北京的公司,java开发,和很多年轻人一样,干了一段时间,我发现 ...
- MFC、WTL、WPF、wxWidgets、Qt、GTK、Cocoa、VCL 各有什么特点?
WTL都算不上什么Framework,就是利用泛型特性对Win API做了层封装,设计思路也没摆脱MFC的影响,实际上用泛型做UI Framework也只能算是一次行为艺术,这个思路下继续发展就会变得 ...
- VCL设计方法概论(自己总结了9条),以及10个值得研究的控件 good
VCL设计方法概论 1. 把Delphi对象改造成一个Windows窗口,主要是要设置Handle和回调函数.在创建一个Windows窗口后,将其句柄赋值给Delphi对象的属性,这个并不难,相当于从 ...
- define预处理以及宏定义
define的定义方式 无参一般形式:#define 标认符 字符串 比如:#define COUTD "%d\n" 带参一般形式:#def ...
- iOS开发笔记--宏定义的黑魔法 - 宏菜鸟起飞手册
宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在 ...
- (转载)C++中将构造函数或析构函数定义为private
(转载)http://www.blogjava.net/fhtdy2004/archive/2009/05/30/278971.html C++中将构造函数或析构函数定义为private 很多情况下要 ...
随机推荐
- java判断某个字符串包含某个字符串的个数
/** * 判断str1中包含str2的个数 * @param str1 * @param str2 * @return counter */ public static int countStr(S ...
- struts2标签详解
struts2标签讲解 要使用Struts2的标签,只需要在JSP页面添加如下一行定义即可:<%@ taglib prefix="s" uri="/struts-t ...
- android开发 解决启动页空白或黑屏问题
遇到的情况: app启动时进入启动页时出现白屏页,然后大概一秒之后就出现了背景图片. 原因:app启动时加载的是windows背景,之后再加载布局文件的,所以开始的黑屏/白屏就是windows的背景颜 ...
- 单点登录(iwantmoon.com出品)
早年便听到单点登录,一直因为感觉很简单,就没有动手去弄,正好现在公司有要求,那么OK,直接做了一个单机版的单点登录. 原理,可以参考SSO. Now,我们来看看我的实现吧.看下图 我们平时所做的登录, ...
- 用PHP向数据库中添加数据
显示页面(用户可见) <body><form action="chuli.php" method="post"> //将该页面接收的数 ...
- CSS3中box-shadow的用法介绍
一般我们通过box-shadow来设置盒阴影,但是有些属性我们一般没有用到,这篇文章将对box-shadow属性进行逐个分析.语法 CSS Code复制内容到剪贴板 E {box-shadow:ins ...
- bzoj 2141 线段树套平衡树
用树套树来解决这个问题,存储每个节点的数值是多少,然后交换 对于答案的变更可以讨论下,假设交换的是x,y位置的数x<=y 如果x=y || high[x]=high[y]则对答案没有影响 如果h ...
- hdu 1028 Ignatius and the Princess III
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1028 题目大意:3=1+1+1=1+2=3 :4=4=1+1+1+1=1+2+1=1+3:所以3有3种 ...
- E3: PS4/PC 莎木3 众筹200万美元 9小时内达成
这次E3任天堂没有新掌机(传说中的XDS呢.呵呵)和口袋的消息, 被喷得很严重, 索尼的FF7重制版和莎木3是亮点. 而莎木3的众筹速度据说创了记录, 玩家的情怀大胜. 笔者看到国内也有赞助几十刀的玩 ...
- 百度Hi之CSRF蠕虫攻击
漏洞起因:百度是国内最大的中文搜索引擎.同时百度也提供了百度空间.百度贴吧等BLOG社区服务,拥有海量的用户群,号称全球最大中文社区. 80sec发现过百度产品一系列的安全漏洞,其中一些问题得到了有效 ...