深入VCL 理解BCB的訊息機制 (一) (轉)

worldblog發表於2007-12-07
深入VCL 理解BCB的訊息機制 (一) (轉)[@more@]

 

 

 

microsoft FrontPage 4.0" name=GENERATOR>

深入VCL 理解BCB的訊息機制

方法1

Written by
CKER

引子

  本文所談及的技術內容都來自於Inte的公開資訊。由CKER在閒暇之際整理後,貼出來以飴網友,姑且妄稱原創。
  『每次在國外網站上找到精彩文章的時候,心中都會暗自嘆息為什麼在中文網站難以覓得這類文章呢?其實原因大家都明白。』

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

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

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

  如果不清楚那就和我一起深入VCL的原始碼看個究竟吧。『注:BCB只有Professional和Enterprise版本才帶有VCL原始碼。當然,大夥的版本都有原始碼的。我沒猜錯吧 :-)

方法1。使用訊息對映(Message Map)過載T的Dispatch虛成員

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

BEGIN_MESSAGE_MAP

VCL_MESSAGE_HANDLER( … …)

END_MESSAGE_MAP( …)

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

在BorlandCBuilder5IncludeVcl找到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的寫法,以免出現問題。

版權說明:
您可以隨意複製、分發、此文件。但未經本人同意,您不可以擷取、改動本文片斷,或用本文謀取任何形式的利益。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989647/,如需轉載,請註明出處,否則將追究法律責任。

相關文章