C++ BUILDER 訊息處理的深入探索 (轉)
在本文中我將告訴你如何以C++Builder來處理訊息,並透過此一能力,來達成在一般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目錄下的Includevclmessages.hpp中,你可以決定要自行解釋TMessage引數或是直接將其轉換成專屬的結構。很抽象嗎?我舉個例子吧,以WM_NCHITTEST訊息來說,C++Builder為它定義了TWMNCHitTest的專屬結構,所以你可以直接經由它來得到XPos、YPos等值。或者你也可以直接由TMessage的LParam取得其值,端看你使用的方便。仔細觀察TMessage及TWMNCHitTest兩個結構,你會發現它們是等價的,也就是說它們的大小是一致的,因此你可以直接用強制轉型互相轉換(這有點類似union的方法)。
struct TMessage
{
Cardinal Msg;
union
{
struct
{
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函式,就可以藉以處理指定的訊息了。前面提到的三個巨集只是將這個程式簡化而已,沒什麼大不了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990999/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 深入理解Android非同步訊息處理機制Android非同步
- 處理檔案上傳時的訊息格式轉換問題
- MPLS RSVP訊息處理——VecloudCloud
- KafkaConsumer對於事務訊息的處理Kafka
- 如何處理錯誤訊息PleaseinstalltheLinuxkernelheaderfilesLinuxHeader
- .net core 訊息流處理流程
- Android中的非同步訊息處理機制Android非同步
- RocketMQ的事務訊息處理【half-message】MQ
- 如何處理RabbitMQ 訊息堆積和訊息丟失問題MQ
- 訊息中介軟體消費到的訊息處理失敗怎麼辦?
- 原始碼分析:Android訊息處理機制原始碼Android
- Android應用程式訊息處理機制Android
- 如何用 Golang 的 channel 實現訊息的批量處理Golang
- 如何用 Golang 的 channel 實現訊息的批次處理Golang
- 回轉壽司你一定吃過!——Android訊息機制(處理)Android
- (轉貼) C++ Builder 2007六月上市 (C/C++) (News)C++UI
- RabbitMQ,RocketMQ,Kafka 事務性,訊息丟失和訊息重複傳送的處理策略MQKafka
- 開心檔之C++ 訊號處理C++
- iOS探索 動態方法解析和訊息轉發機制iOS
- Kafka是如何處理Netflix每天2萬億條訊息的?Kafka
- Cloud Foundry架構和訊息處理機制Cloud架構
- Laravel 實現 Kafka 訊息推送與接收處理LaravelKafka
- 【實戰教程】微信卡券訊息處理
- Handler訊息處理機制原始碼解析 上原始碼
- Kafka中消費者延遲處理訊息Kafka
- iOS探索:Runtime之訊息轉發及動態新增方法iOS
- React應用裡Invalid hook call錯誤訊息的處理ReactHook
- 深入 RPC 訊息協議RPC協議
- 訊息佇列深入解析佇列
- 《球球大作戰》原始碼解析——(9)訊息處理原始碼
- Spring Cloud Stream如何處理訊息重複消費?SpringCloud
- 聊天列表訊息合併,處理相鄰時間
- 阿里雲訊息佇列 RocketMQ 5.0 全新升級:訊息、事件、流融合處理平臺阿里佇列MQ事件
- 如何處理Docker的錯誤訊息request canceled:Docker代理問題Docker
- MQ 訊息佇列的解耦、介面非同步處理、削峰MQ佇列解耦非同步
- CRM中介軟體裡parent not ok的錯誤訊息如何處理
- MQ收到無序的訊息時如何進行業務處理MQ行業
- Windows10 VS2017 C++訊號處理WindowsC++
- Kotlin DSL C++專案引入OpenCV異常處理(轉)KotlinC++OpenCV