Thursday, August 31, 2006

BCB Hook VCL Message (VCL消息的攔截)

◎蕭沖原創

VCL component msg handling:
Event -> ProcessMessage (TApplication)
-> 訊息被傳到指定的VCL,如Form、Button、Label............
-> 該物件的MainWndProc (最初定義在 TWinControl,不可被override)
-> 該物件的WndProc (最初virtual定義在 TControl)
-> 該物件的Dispatch (最初virtual定義在 TObject)
-> 該物件的TWinControl.WMCommand
-> 子物件的Handler (但方法是定義在父類上的)
-> 該物件或子物件的DefaultHandler


A. Hook MSG at WinMain:
1/用Application的OnMessage處理POST的訊息,但對於某些由系統直接send的msg或是user用SendMessage方法傳的msg是無法被trigger的。
1.1/ Application->Run裡的Loop中包含ProcessMessage這個method,而OnMessage則含在它的判別中。
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Handled: Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
begin
Result := True;
if Msg.Message <> WM_QUIT then
begin
Handled := False; //稍後可能經由OnMessage而改變,進而影響DispatchMessage是否被叫
if Assigned(FOnMessage) then FOnMessage(Msg, Handled); //是否有指定OnMessage
if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end
else
FTerminate := True;
end;
end;

2/用HookMainWindow/UnhookMainWindow 改寫TApplication.WndProc中的訊息處理部份。


B. SubClass WndProc:
1/用SubClassing的技術SetWindowLongPtr(),指向另一個新的WndProc,這是最全面性的更改視窗類的處理函式。然後再用CallWindowProc 呼叫原WndProc,最後app結束前再用SetWindowLongPtr原來的WndProc的註冊。 (事實上vcl自己就有用,它先指向InitWindow,然後再轉向MainWndProc)



C. Override default WndProc:
1/ override WndProc 這是全面性的。在TControl裡有個property叫WindowProc,就是指向原始的WndProc,可簡單的透過這個屬性指向自己的method。

D. Override TObject.Dispatch method :

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_XXXX, TWMXXXX, WMXXXX)
END_MESSAGE_MAP(TForm)

這個macro經preprocessing後長得像
virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case WM_XXXX:
WMXXXX(*((TMessage *)Message));
break;

default:
TForm::Dispatch(Message); //呼叫父類別的Dispatch方法 ,類似delphi的inherited
break;

}
}

E. 指定VCL預設的On事件屬性,如OnButtonClick等至自己的handler
1/在每個元件上的on event上指定自己的handler,即一般的操作方法。


F. override TWinControl.DefaultHandler (或是透過屬性FDefWndProc指向自己的handler)。這裡可以處理user define msg的最後一個地方。

No comments: