規範的BCB過程利用Application->Run()進去消息循環,在Application的ProcessMessage措施中,利用PeekMessage措施從消息隊列中提取消息,並將此消息從消息隊列中移除。而後ProcessMessage措施察看是否存在Application->OnMessage措施。存在則轉入此措施處理消息。爾後再將處理過的消息發放給過程當中的各個對象。至此,WndProc措施收到消息,並舉行處理。萬一有沒法處理的交給重載的Dispatch措施來處理。要是還不能處理的話,再交給父類的Dispatch措施處理。最後Dispatch措施切實上將消息轉入DefaultHandler措施來處理。(嘿嘿,切實上,你同樣可以重載DefaultHandler措施來處理消息,然而太晚了一點,我想不曾人甘心最後一個處理消息吧)。函數
1.TApplication的OnMessage事件的利用
在C++Builder開發的利用過程當中,任何窗體接收到一個Windows消息都會引起順次OnMessage事件,於是,可以穿越相應TApplication對象的OnMessage事件來捉拿任何發送給本過程的Windows消息。ui
OnMessage的事件的處理函數原型以下:
typedef void __fastcall (__closure *TMessageEvent ) (tagMsg &Msg,bool &Handled );
這個處理函數有兩個參數,其中參數Msg表示的是被截獲的消息,而參數Handled則用來指示本消息是否曾經處理了結。在過程當中可以穿越設置參數Handled爲true,以免後續的過程處理這個消息,反之把Handled設爲false則批准後繼過程繼續處理這個消息。
必需小心的是,OnMessage事件僅僅接受發送到消息隊列的消息,而直接穿越API函數SendMessage()發送給窗口函數的消息將不會被截獲。另外,當過程運行的時候,OnMessage事件被引起的頻率有可能極其高,於是這個事件的處理函數代碼厲行工夫將直接波及到全副過程的運行效率。spa
2.利用消息照射截獲消息
C++Builder的VCL供給了對大多數Windows消息的處理機制,對於等閒的利用過程是足夠了。然而,VCL也不是森羅萬象的。有的情形下,過程必需處理那些VCL處理不曾處理的Windows消息,可能過程必需屏障某些特定的消息時,則就必需過程員本身捉拿Windows消息。
爲此C++Builder供給了一種消息照射機制,穿越消息照射過程能將特定的Windows消息與對應的處理函數聯繫起來,當窗口捉拿到這個消息時就會積極調用對應的處理函數。
利用消息照射有一下幾個環節:
(1) 消息照射表,把某些消息的處理權交給自定義的消息處理函數。
這麼的消息照射列表該當位於一個組件類的定義中,它以一個不曾參數的BEGIN_MESSAGE_MAP 宏開始,以END_MESSAGE_MAP宏了結。END_MESSAGE_MAP宏的單一參數該當是組件的父類的名字。一般情形下,這個所謂的父類指的即使TForm。在宏BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間插入一個多是多個MESSAGE_HANDLER 宏。
MESSAGE_HANDLER宏將一個消息句柄和一個消息處理函數聯繫在同時。
MESSAGE_HANDLER宏有三個參數:Windows消息名、消息構造體名和對應的消息處理函數名。其中,消息構造體名既可以是通用的消息構造體TMessage,也可以是特定的消息構造體,例如TWMMouse。
在利用消息照射的時候要小心如下兩點:
a.一個窗口類定義中只能有一個消息照射表。
b.消息照射定然位於它所引用的全部消息處理函數聲明的後面。
(2) 在窗口類中聲明消息處理函數
這裏的消息處理函數名和參數都定然和對應的MESSAGE_HANDLER宏統一。
一個標兵的消息處理函數的聲明以下:
void __fastcall 消息處理函數名(消息構造體名 &Message);
例如:
void __fastcall WMNchitTest(TMessage &message);
(3) 了結消息處理函數
消息處理函數的編制和等閒的函數沒什麼太大的差別,單一不一樣的是,等閒在此函數的最後要加上一條語句 TForm::Dispatch(&Message),以了結VCL對於消息的默認處理。萬一不曾這一句,消息將會被全面堵截;在某些情形下,VCL可能會由於得不到消息而沒法工做。orm
3.重載WndProc()函數
在某些情形下,過程必需捉拿可能屏障某些特定的消息,這時可以用前面推薦的消息照射的措施。固然,這種措施也不是單一的,也可以穿越重載窗口函數WndProc()來了結。由於系統將在調用函數Dispatch()派發消息以前調用窗口函數WndProc(),於是,可以穿越重載函數WndProc()得到一個在分配消息以前過濾消息的時機。
這個消息處理的窗口函數的原型以下:
virtual void __fastcall WndProc(TMessage &Message);
例如:(翔實請看NowCane452.com的例子)
void __fastcall TForm1::WndProc(TMessage &Message)
{
PCOPYDATASTRUCT pMyCDS;
if(Message.Msg==g_MyMsg)
{
ShowMessage("收到登記消息,wParam="+IntToStr(Message.WParam)+" lParam="+IntToStr(Message.LParam));
Message.Result=0;//消息處理的收穫,固然在本例中沒故含義。
}
else if(Message.Msg==g_MyMsg1)
{
Application->MessageBoxA((char *)Message.LParam,"收到發送方的字符串",MB_OK);
}
else if(Message.Msg==WM_COPYDATA)
{
pMyCDS = (PCOPYDATASTRUCT)Message.LParam;
Application->MessageBoxA((char *)pMyCDS->lpData,"收到發送方的字符串",MB_OK);
}對象
TForm::WndProc(Message);//其餘的消息繼續遞交下去
}
乍看起來,這和重載Dispatch措施好象差很少。但切實上仍是有差別的。差別就在先後次序上,消息是先交給WndProc來處理,最後才調用Dispatch措施的。這麼,重載WndProc措施可以比重載Dispatch措施更早一點點得到消息並處理消息。隊列
4.Application->HookMainWindow措施
萬一您計劃利用Application->OnMessage來捉拿全部發送至您的利用過程的消息的話,您可能要絕望了。它沒法捉拿利用SendMessage直接發送給窗口的消息,由於這不穿越消息隊列。您可能會說我可以直接重載TApplication的WndProc措施。呵呵,不可以。由於TApplication的WndProc措施被Borland聲明爲靜態的,從而沒法重載。顯而易見,這麼作的原由極可能是Borland擔憂其所帶來的反作用。那該如何是好呢?察看TApplication的WndProc的pascal源碼可以看到:
procedure TApplication.WndProc(var Message: TMessage);
... // 節儉篇幅,這裏與主題無關代碼略去
begin
try
Message.Result := 0;
for I := 0 to FWindowHooks.Count - 1 do
if TWindowHook(FWindowHooks[I]^)(Message) then Exit;
... // 節儉篇幅,這裏與主題無關代碼略去
WndProc措施一開始先調用HookMainWindow掛鉤的自定義消息處理措施,而後再調用缺省過程處理消息。這麼利用HookMainWindow就可以在WndProc其中接加入本身的消息處理措施。利用這個措施響應SendMessage發送來的消息很管用。最後提醒一下,利用HookMainWindow掛鉤爾後定然要對應的調用UnhookMainWindow卸載鉤子過程。給個例子:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Application->HookMainWindow(AppHookFunc);
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::AppHookFunc(TMessage &Message)
{
bool Handled ;
switch (Message.Msg)
{
case WM_CLOSE:
mrYes==MessageDlg(xg.sy-xghg.com"Really Close??", mtWarning, TMsgDlgButtons() << mbYes <
Handled = false : Handled = true ;
break;
}
return Handled;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
Application->UnhookMainWindow(AppHookFunc);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SendMessage(Application->Handle,WM_CLOSE,0,0);
}
//---------------------------------------------------------------------------事件
5.本身發送消息
利用過程也可以像Windows系統同樣在窗口多是組件之間發送消息。C++Builder爲此供給了幾種門徑:利用函數TControl::Perform()可能API函數SendMessage()和PostMessage()向特定的窗體發送消息,多是利用函數TWinControl::Broadcast()和API函數BroadcastSystemMessage()廣播消息。ip
Perform()函數的做用即使將指定的消息遞交給TControl的WndProc過程,實用於全部由TControl類派生的對象,Perform()原型以下:
int __fastcall Perform(unsigned Msg, int WParam, int LParam);
要等到消息處理爾後才歸來。ci
在統一個利用過程的不一樣學體和控件之間利用函數Perform()是極其方便的。然而這個函數是TControl類的成員函數。也即使說,利用它時,過程定然懂得這個接受消息的控件的實例。而在衆多情形下過程並不懂得這個接受消息的窗體的實例而只是懂得這個窗體的句柄,例如,在不一樣利用過程的窗體之間發送消息就屬於這種情形。這時,函數Perform()顯明沒法利用,取而代之的該當是函數SendMessage()和PostMessage()。開發
函數SendMessage()和PostMessage()的功能大約上同樣,它們都可以用來向一個特定的窗口句柄發送消息。重要的差別是,函數SendMessage()直接把一個消息發送給窗口函數,等消息被處理爾後才歸來;而函數PostMessage()則只是把消息發送到消息隊列,而後就即刻歸來。
這兩個函數的原型聲明離別以下:
LRESULT SendMessage(HWND hWnd,UINRT Msg,WPARAM,wParam,LPARAM,lParam);
BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM,wParam,LPARAM,lParam);
可以看到,這兩個函數參數同函數Perform()極其相仿,只是添置了一個hWnd參數用以表示目標窗口的句柄。
Broadcast()和BroadcastSystemMessage()函數Broadcast()實用於全部由TWinControl類派生的對象,它可以向窗體上的全部子控件廣播消息。其函數原型以下:void __fastcall Broadcast(void *Message);可以看到,這個函數只有一個Message參數,它指向被廣播的TMessage種類的消息構造體。函數Broadcast()只能向C++Builder利用過程當中的指定窗體上的全部子控件廣播消息,萬一要向系統中其餘利用過程可能窗體廣播消息,函數Broadcast()就無能爲力了。這時可以利用API函數BroadcastSystemMessage(),這個函數可以向任意的利用過程可能組件廣播消息。其函數原型以下:long BroadcastSystemMessage(DWORD dwFlags,LPWORD lpdwRecipients,UINT uiMessage,WPAREM wParam,LPARAM lParam);