C++ BUILDER 消息处理的深入探索

在本文中我將告訴你如何以C++Builder來處理Windows訊息,並透過此一能力,來達成在一般VCL元件所無法做到的功能。

何謂Window訊息(Message)

大家都知道 Windows是一套以訊息驅動(Message Driven)的作業系統。然而對於訊息本身卻諱莫如深,只知其然而不知其所以然,雖然C++Builder將某些Windows訊息封裝於事件(Event)系統中,但身為一個Windows程式設計師,實有必要瞭解Windows的訊息系統。

所謂訊息是由Windows作業系統送往程式的事件。它是系統中各個物件溝通的方式,舉例來說,當移動滑鼠、按下滑鼠鍵、改變視窗大小時,Windows都會送出訊息以通知程式。當然,為了要辨別事件的內容,Windows系統中定義了許多的訊息,如WM_PAINT,WM_CHAR等等。

當事件發生時,Windows會判斷該事件必須由那個程式接收,然後將事件以訊息的方式送往程式的視窗中。雖然在Windows系統中包含了數以百計的事件,但是作業系統並沒有為各個事件設計不同的訊息結構,而是以一個一般性的結構來描述訊息,這個結構在C++Builder就稱是TMessage。

當然,隨著事件的不同,對於訊息的解釋也有所不同,在C++Builder中也為各種常用的訊息定義了專屬的結構,你可以直接使用它們來解釋訊息。這些訊息定義在C++Builder目錄下的Include\vcl\messages.hpp中,你可以決定要自行解釋TMessage參數或是直接將其轉換成專屬的結構。很抽象嗎?我舉個例子吧,以WM_NCHITTEST訊息來說,C++Builder為它定義了TWMNCHitTest的專屬結構,所以你可以直接經由它來得到XPos、YPos等值。或者你也可以直接由TMessage的LParam取得其值,端看你使用的方便。仔細觀察TMessage及TWMNCHitTest兩個結構,你會發現它們是等價的,也就是說它們的大小是一致的,因此你可以直接用強制轉型互相轉換(這有點類似union的方法)。

struct TMessage

{

Cardinal Msg;

union

{

struct

{

Word WParamLo;

Word WParamHi;

Word LParamLo;

Word LParamHi;

Word ResultLo;

Word ResultHi;

};

struct

{

long WParam;

long LParam;

long Result;

};

};

};

struct TWMNCHitTest

{

Cardinal Msg;

long Unused;

union

{

struct

{

Windows::TSmallPoint Pos;

long Result;

};

struct

{

short XPos;

short YPos;

};

};

} ;

在收到訊息後,程式必須處理該訊息,若是不處理,則可直接將它交給Windows的內定處理程序來處理之,若是程式需要傳回值,也可以在此時傳回,Windows會將該值傳回給呼叫方。如此就完成了訊息傳遞的程序。

WM_NCHITTEST訊息的奧秘

WM_NCHITTEST訊息是一個很特殊的訊息。它是用來決定目前滑鼠所在位置屬性的訊息,因此我們可以利用此特性,當滑鼠移至指定的位置時,傳回 HTCAPTION,使得系統以為滑鼠目前位於標題棒,如此你就可以移動視窗了。如何?是不是很神奇呢?

由上可知,只要我們適時地攔截WM_NCHITTEST訊息,然後傳回HTCAPTION,就可以順利地欺騙系統,達成在任何位置模擬出標題棒的效果。

C++ Builder的處理訊息的巨集

在C++Builder為了處理訊息的方便,因此定義了三個處理訊息的巨集(Macro)。

BEGIN_MESSAGE_MAP

MESSAGE_HANDLER(WM_NCHITTEST,TMessage,OnNcHitTest)

END_MESSAGE_MAP(TForm)

以上的三個巨集BEGIN_MESSAGE_MAP、MESSAGE_HANDLER及END_MESSAGE就是C++ Builder定義的巨集,其中比較重要的是MESSAGE_HANDLER;它共需要三個參數,第一個參數代表訊息的ID,第二個代表參數型態,最後一個則是訊息事件處理函數。

乍看之下,這個巨集似乎和MFC及OWL所使用的巨集有幾分神似,沒錯,不過其機制卻更為簡單及簡潔,我們可以看看C++Builder對於這三個巨集的原始定義:

#define BEGIN_MESSAGE_MAP virtual void __fastcall Dispatch(void *Message) \

{ \

switch (((PMessage)Message)->Msg) \

{

#define MESSAGE_HANDLER(msg,type,meth) \

case msg: \

meth(*((type *)Message)); \

break;

#define END_MESSAGE_MAP(base) default: \

base::Dispatch(Message); \

break; \

} \

}

相較於MFC或 OWL的可怕巨集,它實在是簡單多了,這是因為C++Builder已替你完成了大部份的工作。其實若我們把以上的巨集展開後,可以得到以下的結果:

virtual void __fastcall Dispatch(void *Message)

{

switch (((PMessage)Message)->Msg)

{

case WM_NCHITTEST:

OnNcHitTest(*((TMessage *)Message));

break;

default:

TForm::Dispatch(Message);

break;

}

}

怎麼樣?展開之後是不是有恍然大悟的感覺,要弄清楚這個巨集在賣啥膏藥是很容易的,如果你玩過MFC的訊息處理機制,再看到以上的巨集,相較之下,實在是小兒科,不過也就因其簡單,所以C++Builder的優勢益加彰顯。

我簡單地說明以上的程式:在每個TForm中都定義一個名為Dispatch的虛擬函式,它就是用來處理Windows的訊息的,在大部份情況下,訊息都是呼叫C++Builder所提供的處理函式,因此你不需要修改它。

換句話說,我們只要改寫Dispatch函式,就可以藉以處理指定的訊息了。前面提到的三個巨集只是將這個程序簡化而已,沒什麼大不了。

C++ BUILDER 消息处理的深入探索相关推荐

  1. 看看第七届phpcon大会的大佬,真的很佩服

    今年没有去看phpcon大会,有点遗憾. 看了今年参会的大佬,很是佩服啊. 听说今年因为上周六的强台风经过上海的缘故,鸟哥没有到场,有点遗憾. 去年(2018年)公司组织去参加这个会议了,地点还是老地 ...

  2. .net core发布 正在发现数据上下文_Tableau 2020.4 正式发布,即刻探索浏览器中的 Tableau Prep Builder、空间增强等新功能...

    Tableau 2020.4 最新版本现已问世!本次重磅推出浏览器中的 Tableau Prep Builder.地图支持多个标记层.适用于 Linux 版 Tableau Server 的资源监视工 ...

  3. Android源码设计模式探索与实战【建造者模式】

    IT行业,一直讲一句话,拼到最后都拼的是"内功",而内功往往就是指我们处理问题的思路.经验.想法,而对于开发者来说,甚至对于产品也一样,都离不开一个"宝典",就 ...

  4. 深入探索Android卡顿优化

    由于卡顿优化这一主题包含的内容太多,为了更详细地进行讲解,因此,笔者将它分为了上.下两篇.本篇,即为<深入探索Android卡顿优化>的上篇. 本篇包含的主要内容如下所示: 卡顿优化分析方 ...

  5. C++Builder 资料库 (转载)

    C++Builder 资料库 2005-03-03 15:14 13115人阅读 评论(3) 收藏 举报 1.怎样在C++Builder中创建使用DLL 2.用C++Bulider在WIN.INI中保 ...

  6. C++Builder 资料库

    转自: http://blog.csdn.net/chiengod/article/details/309466 1.怎样在C++Builder中创建使用DLL  2.用C++Bulider在WIN. ...

  7. C++ Builder 杂项

    1.怎样在C++Builder中创建使用DLL 2.用C++Bulider在WIN.INI中保存信息 3.如何在C++Builder中检测硬件 4.C++Builder如何响应消息及自定义消息 5.利 ...

  8. 许多代码段,没准儿有你需要的 C++ Builder

    1.怎样在C++Builder中创建使用DLL 2.用C++Bulider在WIN.INI中保存信息 3.如何在C++Builder中检测硬件 4.C++Builder如何响应消息及自定义消息 5.利 ...

  9. ]许多代码段,没准儿有你需要的 C++ Builder

    [code:1:d5dc046d55] 1.怎样在C++Builder中创建使用DLL 2.用C++Bulider在WIN.INI中保存信息 3.如何在C++Builder中检测硬件 4.C++Bui ...

最新文章

  1. php 缓存模块,PHP缓存之模块缓存(APC)_PHP教程
  2. 【怎样写代码】工厂三兄弟之抽象工厂模式(三):产品等级结构与产品族
  3. Optimized Purchasing基础知识
  4. ubuntu MySQL Oracle_Oracle 与 MySql 区别
  5. postman安装和简单使用
  6. 关于二维数组取地址加以或减一解引用问题
  7. Python中68个内置函数的总结
  8. Mysql 声明变量
  9. Web API路由与动作(三)
  10. 延时摄影制作软件——GlueMotion for Mac支持m1
  11. SQL-55 分页查询employees表,每5行一页,返回第2页的数据
  12. html 5个人博客代码模板,5套漂亮的个人博客html模板分享
  13. 研发流程——变更流程管控
  14. HDU6357 Hills And Valleys
  15. 喜马拉雅主播工具软件:图片OCR文字识别自动转成mp3高品质语音文件
  16. 树莓派写卡后连接诸多问题及方法
  17. Deeply Learned Attributes for Crowded Scene Understanding
  18. linux trac svn,Ubuntu安装Trac SVN
  19. 怎么用计算机玩绝地求生,8g内存玩绝地求生卡顿怎么办?绝地求生大逃杀内存设置优化图文教程...
  20. 通用的商城系统后台管理ui框架模板

热门文章

  1. jsonpath的用法
  2. 用互斥锁实现程序只能有一个实例
  3. .Net Core 在 Linux-Centos上的部署实战教程(二)
  4. 如何创建一个新浪微博应用以及获得Access token
  5. JS实现App扫码网页端登录
  6. mysql安装可能遇到的错误和安装过程
  7. Windows Server Backup 裸机恢复
  8. YTU 2887: D--机器人Bill
  9. unicode and utf-8
  10. 中科燕园GIS外包-----基于ArcGIS的应急平台