C Builder中如何利用消息
規范的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消息。
OnMessage的事件的處理函數原型如下:
typedef void __fastcall (__closure *TMessageEvent ) (tagMsg &Msg,bool &Handled );
這個處理函數有兩個參數,其中參數Msg表示的是被截獲的消息,而參數Handled則用來指示本消息是否曾經處理告終。在過程中能夠穿越設置參數Handled為true,以避免后續的過程處理這個消息,反之把Handled設為false則批準后繼過程繼續處理這個消息。
必需當心的是,OnMessage事件僅僅接受發送到消息隊列的消息,而直接穿越API函數SendMessage()發送給窗口函數的消息將不會被截獲。另外,當過程運行的時候,OnMessage事件被引發的頻率有可能極其高,因而這個事件的處理函數代碼厲行工夫將直接波及到全副過程的運行效率。
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可能會因為得不到消息而無法工作。
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()廣播消息。
Perform()函數的作用即便將指定的消息遞交給TControl的WndProc過程,實用于所有由TControl類派生的對象,Perform()原型如下:
int __fastcall Perform(unsigned Msg, int WParam, int LParam);
要等到消息處理爾后才歸來。
在統一個利用過程的不同學體和控件之間利用函數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
);
轉載于:https://www.cnblogs.com/hanny/p/7782935.html
總結
以上是生活随笔為你收集整理的C Builder中如何利用消息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HBase:分布式列式NoSQL数据库
- 下一篇: PageObjects 设计模式