程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深入VCL理解BCB的消息機制1

深入VCL理解BCB的消息機制1

編輯:關於C++

本文所談及的技術內容都來自於Internet的公開信息。由CKER在閒暇之際整理後,貼出來以飴網友,姑且妄稱原創。

『每次在國外網站上找到精彩文章的時候,心中都會暗自歎息為什麼在中文網站難以覓得這類文章呢?其實原因大家都明白。』

時至今日,學習Windows編程的兄弟們都知道消息機制的重要性。所以理解消息機制也成了不可或缺的功課。

大家都知道,Borland的C++ Builder以及Delphi的核心是VCL。作為Win32平台上的開發工具,封裝Windows的消息機制當然也是必不可少的。

那麼,在C++ Builder中處理消息的方法有哪些呢?它們之間的區別又在哪裡?如果您很清楚這些,呵呵,對不起啦,請關掉這個窗口。

如果不清楚那就和我一起深入VCL的源碼看個究竟吧。『注:BCB只有Professional和Enterprise版本才帶有VCL源碼。當然,大伙的版本都有源碼的。我沒猜錯吧 :-)<CKER用的是BCB5>』

方法1。使用消息映射(Message Map)重載TObject的Dispatch虛成員函數

這個方法大家用的很多。形式如下

BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER( … …)
END_MESSAGE_MAP( …)

但這幾句話實在太突兀,C++標准中沒有這樣的定義。不用講,這顯然又是宏定義。它們到底怎麼來的呢?CKER第一次見到它們的時候,百思不得其解。嘿嘿,不深入VCL,怎麼可能理解?

在\Borland\CBuilder5\Include\Vcl找到sysmac.h,其中有如下的預編譯宏定義:

#define BEGIN_MESSAGE_MAP virtual void __fastcall Dispatch(void *Message) \
     { \
       switch (((PMessage)Message)->Msg) \
       {
#define VCL_MESSAGE_HANDLER(msg,type,meth) \
        case msg: \
           meth(*((type *)Message)); \
        break;
// NOTE: ATL defines a MESSAGE_HANDLER macro which conflicts with VCL's macro. The
// VCL macro has been renamed to VCL_MESSAGE_HANDLER. If you are not using ATL,
// MESSAGE_HANDLER is defined as in previous versions of BCB.
file://
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER VCL_MESSAGE_HANDLER
#endif // ATL_COMPAT
#define END_MESSAGE_MAP(base)
        default: \
          base::Dispatch(Message); \
        break; \
       } \
     }

這樣對如下的例子:

BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_PAINT,TMessage,OnPaint)
END_MESSAGE_MAP(TForm1)

在預編譯時,就被展開成如下的代碼

virtual void __fastcall Dispatch(void *Message)
{
    switch (((PMessage)Message)->Msg)
    {
     case WM_PAINT:
         OnPaint(*((TMessage *)Message)); //消息響應句柄,也就是響應消息的成員函數,在Form1中定義
     break;
     default:
         Form1::Dispatch(Message);
     break;
    }
}

這樣就很順眼了,對吧。對這種方法有兩點要解釋一下:

1。virtual void __fastcall Dispatch(void *Message) 這個虛方法的定義最早可以在TObject的定義中找到。打開

BCB的幫助,查找TForm的Method(方法),你會發現這裡很清楚的寫著Dispatch方法繼承自TObject。如果您關心VCL的繼承機制的話,您會發現TObject是所有VCL對象的基類。TObject的抽象凝聚了Borland的工程師們的心血。如果有興趣。您應該好好查看一下TObject的定義。

很顯然,所有Tobject的子類都可以重載基類的Dispatch方法,來實現自己的消息調用。如果Dispatch方法找不到此消息的定義,會將此消息交由TObject::DefaultHandler方法來處理。抽象基類TObject的DefaultHandler方法實際上是空的。同樣要由繼承子類重載實現它們自己的消息處理過程。

2。很多時候,我見到的第二行是這樣寫的:

MESSAGE_HANDLER(WM_PAINT,TMessage,OnPaint)

在這裡,您可以很清楚的看到幾行注解,意思是ATL中同樣包含了一個MESSAGE_HANDLER的宏定義,這與VCL發生了沖突。為了解決這個問題,Borland改用VCL_MESSAGE_HANDLER這樣的寫法。

當您沒有使用ATL的時候,MESSAGE_HANDLER將轉換成VCL_MESSAGE_HANDLER。但如果您使用了ATL的話,就會有問題。所以我建議您始終使用VCL_MESSAGE_HANDLER的寫法,以免出現問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved