C Builder中如何利用消息
規(guī)范的BCB過程利用Application->Run()進(jìn)去消息循環(huán),在Application的ProcessMessage措施中,利用PeekMessage措施從消息隊(duì)列中提取消息,并將此消息從消息隊(duì)列中移除。然后ProcessMessage措施察看是否存在Application->OnMessage措施。存在則轉(zhuǎn)入此措施處理消息。爾后再將處理過的消息發(fā)放給過程中的各個(gè)對(duì)象。至此,WndProc措施收到消息,并舉行處理。萬一有無法處理的交給重載的Dispatch措施來處理。要是還不能處理的話,再交給父類的Dispatch措施處理。最后Dispatch措施切實(shí)上將消息轉(zhuǎn)入DefaultHandler措施來處理。(嘿嘿,切實(shí)上,你一樣能夠重載DefaultHandler措施來處理消息,然而太晚了一點(diǎn),我想未曾人甘心最后一個(gè)處理消息吧)。
1.TApplication的OnMessage事件的利用
在C++Builder開發(fā)的利用過程中,任何窗體接收到一個(gè)Windows消息都會(huì)引發(fā)順次OnMessage事件,因而,能夠穿越相應(yīng)TApplication對(duì)象的OnMessage事件來捉拿任何發(fā)送給本過程的Windows消息。
OnMessage的事件的處理函數(shù)原型如下:
typedef void __fastcall (__closure *TMessageEvent ) (tagMsg &Msg,bool &Handled );
這個(gè)處理函數(shù)有兩個(gè)參數(shù),其中參數(shù)Msg表示的是被截獲的消息,而參數(shù)Handled則用來指示本消息是否曾經(jīng)處理告終。在過程中能夠穿越設(shè)置參數(shù)Handled為true,以避免后續(xù)的過程處理這個(gè)消息,反之把Handled設(shè)為false則批準(zhǔn)后繼過程繼續(xù)處理這個(gè)消息。
必需當(dāng)心的是,OnMessage事件僅僅接受發(fā)送到消息隊(duì)列的消息,而直接穿越API函數(shù)SendMessage()發(fā)送給窗口函數(shù)的消息將不會(huì)被截獲。另外,當(dāng)過程運(yùn)行的時(shí)候,OnMessage事件被引發(fā)的頻率有可能極其高,因而這個(gè)事件的處理函數(shù)代碼厲行工夫?qū)⒅苯硬暗饺边^程的運(yùn)行效率。
2.利用消息照射截獲消息
C++Builder的VCL供給了對(duì)大多數(shù)Windows消息的處理機(jī)制,對(duì)于等閑的利用過程是足夠了。然而,VCL也不是森羅萬象的。有的情形下,過程必需處理那些VCL處理未曾處理的Windows消息,可能過程必需屏障某些特定的消息時(shí),則就必需過程員自己捉拿Windows消息。
為此C++Builder供給了一種消息照射機(jī)制,穿越消息照射過程能將特定的Windows消息與對(duì)應(yīng)的處理函數(shù)聯(lián)系起來,當(dāng)窗口捉拿到這個(gè)消息時(shí)就會(huì)積極調(diào)用對(duì)應(yīng)的處理函數(shù)。
利用消息照射有一下幾個(gè)環(huán)節(jié):
(1) 消息照射表,把某些消息的處理權(quán)交給自定義的消息處理函數(shù)。
這么的消息照射列表該當(dāng)位于一個(gè)組件類的定義中,它以一個(gè)未曾參數(shù)的BEGIN_MESSAGE_MAP 宏開始,以END_MESSAGE_MAP宏告終。END_MESSAGE_MAP宏的單一參數(shù)該當(dāng)是組件的父類的名字。通常情形下,這個(gè)所謂的父類指的即便TForm。在宏BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間插入一個(gè)可能是多個(gè)MESSAGE_HANDLER 宏。
MESSAGE_HANDLER宏將一個(gè)消息句柄和一個(gè)消息處理函數(shù)聯(lián)系在同時(shí)。
MESSAGE_HANDLER宏有三個(gè)參數(shù):Windows消息名、消息構(gòu)造體名和對(duì)應(yīng)的消息處理函數(shù)名。其中,消息構(gòu)造體名既能夠是通用的消息構(gòu)造體TMessage,也能夠是特定的消息構(gòu)造體,例如TWMMouse。
在利用消息照射的時(shí)候要當(dāng)心以下兩點(diǎn):
a.一個(gè)窗口類定義中只能有一個(gè)消息照射表。
b.消息照射定然位于它所引用的所有消息處理函數(shù)聲明的后面。
(2) 在窗口類中聲明消息處理函數(shù)
這里的消息處理函數(shù)名和參數(shù)都定然和對(duì)應(yīng)的MESSAGE_HANDLER宏統(tǒng)一。
一個(gè)標(biāo)兵的消息處理函數(shù)的聲明如下:
void __fastcall 消息處理函數(shù)名(消息構(gòu)造體名 &Message);
例如:
void __fastcall WMNchitTest(TMessage &message);
(3) 告終消息處理函數(shù)
消息處理函數(shù)的編制和等閑的函數(shù)沒什么太大的差異,單一不同的是,等閑在此函數(shù)的最后要加上一條語句 TForm::Dispatch(&Message),以告終VCL對(duì)于消息的默認(rèn)處理。萬一未曾這一句,消息將會(huì)被全面堵截;在某些情形下,VCL可能會(huì)因?yàn)榈貌坏较⒍鵁o法工作。
3.重載WndProc()函數(shù)
在某些情形下,過程必需捉拿可能屏障某些特定的消息,這時(shí)能夠用前面推薦的消息照射的措施。當(dāng)然,這種措施也不是單一的,也能夠穿越重載窗口函數(shù)WndProc()來告終。因?yàn)橄到y(tǒng)將在調(diào)用函數(shù)Dispatch()派發(fā)消息之前調(diào)用窗口函數(shù)WndProc(),因而,能夠穿越重載函數(shù)WndProc()獲得一個(gè)在分配消息之前過濾消息的時(shí)機(jī)。
這個(gè)消息處理的窗口函數(shù)的原型如下:
virtual void __fastcall WndProc(TMessage &Message);
例如:(翔實(shí)請(qǐng)看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;//消息處理的收獲,當(dāng)然在本例中沒故含義。
}
else if(Message.Msg==g_MyMsg1)
{
Application->MessageBoxA((char *)Message.LParam,"收到發(fā)送方的字符串",MB_OK);
}
else if(Message.Msg==WM_COPYDATA)
{
pMyCDS = (PCOPYDATASTRUCT)Message.LParam;
Application->MessageBoxA((char *)pMyCDS->lpData,"收到發(fā)送方的字符串",MB_OK);
}
TForm::WndProc(Message);//其他的消息繼續(xù)遞交下去
}
乍看起來,這和重載Dispatch措施好象差不多。但切實(shí)上還是有差異的。差異就在前后次序上,消息是先交給WndProc來處理,最后才調(diào)用Dispatch措施的。這么,重載WndProc措施能夠比重載Dispatch措施更早一點(diǎn)點(diǎn)獲得消息并處理消息。
4.Application->HookMainWindow措施
萬一您計(jì)劃利用Application->OnMessage來捉拿所有發(fā)送至您的利用過程的消息的話,您可能要絕望了。它無法捉拿利用SendMessage直接發(fā)送給窗口的消息,因?yàn)檫@不穿越消息隊(duì)列。您可能會(huì)說我能夠直接重載TApplication的WndProc措施。呵呵,不能夠。因?yàn)門Application的WndProc措施被Borland聲明為靜態(tài)的,從而無法重載。顯而易見,這么做的起因很可能是Borland擔(dān)心其所帶來的副作用。那該如何是好呢?察看TApplication的WndProc的pascal源碼能夠看到:
procedure TApplication.WndProc(var Message: TMessage);
... // 節(jié)儉篇幅,這里與主題無關(guān)代碼略去
begin
try
Message.Result := 0;
for I := 0 to FWindowHooks.Count - 1 do
if TWindowHook(FWindowHooks[I]^)(Message) then Exit;
... // 節(jié)儉篇幅,這里與主題無關(guān)代碼略去
WndProc措施一開始先調(diào)用HookMainWindow掛鉤的自定義消息處理措施,然后再調(diào)用缺省過程處理消息。這么利用HookMainWindow就能夠在WndProc其中接加入自己的消息處理措施。利用這個(gè)措施響應(yīng)SendMessage發(fā)送來的消息很管用。最后提醒一下,利用HookMainWindow掛鉤爾后定然要對(duì)應(yīng)的調(diào)用UnhookMainWindow卸載鉤子過程。給個(gè)例子:
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.自己發(fā)送消息
利用過程也能夠像Windows系統(tǒng)一樣在窗口可能是組件之間發(fā)送消息。C++Builder為此供給了幾種門徑:利用函數(shù)TControl::Perform()可能API函數(shù)SendMessage()和PostMessage()向特定的窗體發(fā)送消息,可能是利用函數(shù)TWinControl::Broadcast()和API函數(shù)BroadcastSystemMessage()廣播消息。
Perform()函數(shù)的作用即便將指定的消息遞交給TControl的WndProc過程,實(shí)用于所有由TControl類派生的對(duì)象,Perform()原型如下:
int __fastcall Perform(unsigned Msg, int WParam, int LParam);
要等到消息處理爾后才歸來。
在統(tǒng)一個(gè)利用過程的不同學(xué)體和控件之間利用函數(shù)Perform()是極其方便的。然而這個(gè)函數(shù)是TControl類的成員函數(shù)。也即便說,利用它時(shí),過程定然懂得這個(gè)接受消息的控件的實(shí)例。而在眾多情形下過程并不懂得這個(gè)接受消息的窗體的實(shí)例而只是懂得這個(gè)窗體的句柄,例如,在不同利用過程的窗體之間發(fā)送消息就屬于這種情形。這時(shí),函數(shù)Perform()顯明無法利用,取而代之的該當(dāng)是函數(shù)SendMessage()和PostMessage()。
函數(shù)SendMessage()和PostMessage()的功能大約上一樣,它們都能夠用來向一個(gè)特定的窗口句柄發(fā)送消息。重要的差異是,函數(shù)SendMessage()直接把一個(gè)消息發(fā)送給窗口函數(shù),等消息被處理爾后才歸來;而函數(shù)PostMessage()則只是把消息發(fā)送到消息隊(duì)列,然后就即刻歸來。
這兩個(gè)函數(shù)的原型聲明離別如下:
LRESULT SendMessage(HWND hWnd,UINRT Msg,WPARAM,wParam,LPARAM,lParam);
BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM,wParam,LPARAM,lParam);
能夠看到,這兩個(gè)函數(shù)參數(shù)同函數(shù)Perform()極其相仿,只是添置了一個(gè)hWnd參數(shù)用以表示目標(biāo)窗口的句柄。
Broadcast()和BroadcastSystemMessage()
函數(shù)Broadcast()實(shí)用于所有由TWinControl類派生的對(duì)象,它能夠向窗體上的所有子控件廣播消息。其函數(shù)原型如下:
void __fastcall Broadcast(void *Message);
能夠看到,這個(gè)函數(shù)只有一個(gè)Message參數(shù),它指向被廣播的TMessage種類的消息構(gòu)造體。
函數(shù)Broadcast()只能向C++Builder利用過程中的指定窗體上的所有子控件廣播消息,萬一要向系統(tǒng)中其他利用過程可能窗體廣播消息,函數(shù)Broadcast()就無能為力了。這時(shí)能夠利用API函數(shù)BroadcastSystemMessage(),這個(gè)函數(shù)能夠向任意的利用過程可能組件廣播消息。其函數(shù)原型如下:
long BroadcastSystemMessage(
DWORD dwFlags,
LPWORD lpdwRecipients,
UINT uiMessage,
WPAREM wParam,
LPARAM lParam
);
轉(zhuǎn)載于:https://www.cnblogs.com/hanny/p/7782935.html
總結(jié)
以上是生活随笔為你收集整理的C Builder中如何利用消息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HBase:分布式列式NoSQL数据库
- 下一篇: day27 CRM delete act