前言
雖然C++Builder為一RAD式的程式發展工具,程式設計師在大多數情況下不需理會Windows訊息的細節,只要將心思放在軟體元件的事件處理函式即可。然而由於Windows作業系統終究是一個以訊息驅動的系統,因此架構其上的的應用程式自然無法自外於系統之外,在遭遇到C++Builder沒有定義的事件時,Windows訊息處理能力仍然是C++Builder程式人不可或缺的能力。
不可否認地,C++Builder所提供的事件處理能力已具備了某一程度的完備性,然而我們也必須承認,在C++Buider建構的VCL美麗新世界中,仍然不免有漏網之魚。例如使用者自定訊息的處理,Winsock訊息的處理及一些Windows訊息如WM_NC**** 系列的訊息都是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目錄下的Includevclmessages.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會將該值傳回給呼叫方。如此就完成了訊息傳遞的程序。