![]() Last edit: 05-03-17 Graham Wideman |
Delphi |
Delphi VCL Message Handling Article created: 98-09-30 |
This page is simply a collection of notes on the flow of windows messages through the Delphi VCL "windows procs". This is a topic significant to designing a component which can "hook" another component's message handler, a technique needed for possible Drag or Drop components.
Overview: Delphi Help page "Dispatching messages".
Reference: Delphi Developers Handbook (Cantu and others).
TControl = class(TComponent)
protected
procedure WndProc(var Message: TMessage); virtual;
public
property WindowProc: TWndMethod read FWindowProc write
FWindowProc;
procedure DefaultHandler(var Message); override;
TWinControl = class(TControl)
protected
property DefWndProc: Pointer read FDefWndProc write FDefWndProc;
procedure MainWndProc(var Message: TMessage);
public
procedure DefaultHandler(var Message); override;
Non-Object function:
function InitWndProc(HWindow: HWnd; Message, WParam: Longint; LParam:
Longint): Longint; stdcall;
Deduced from VCL source code:
Call sequence | Comment | How initialized | |
System has WM_xxx for TWinControlDescendant (TWCD) | see table below | ||
proc | TWCD.MainWinProc | probably not overriden, thus: TWinControl.MainWinProc | |
prop | TWCD.WindowProc | can be hooked | TControl.Create |
proc | TWCD.WndProc | default (or end of hook chain) | |
proc | TControl.WinProc | descendants call inherited | |
proc | TObject.Dispatch | specific message handler if any (ie: procedure with "message" directive)... otherwise... | |
proc | TWCD.DefaultHandler | ||
proc | TWinControl.DefaultHandler | descendants call inherited | |
prop | FDefWndProc | TWinControl.Create calls TWinControl.CreateParams sets FDefWndProc := DefWindowProc() | |
system | Default system window proc for this control class | ... or... | |
proc | TControl.DefaultHandler | (only if no handle) | |
TWinControl.CreateWnd registers TWinControl.MainWndProc as the proc the the system should call with messages. Details:
Separate steps | Action |
TWinControl.Create | FObjectInstance := MakeObjectInstance(MainWndProc); |
TWinControl.CreateWnd | WindowClass.lpfnWndProc := @InitWndProc; [...] Windows.RegisterClass(WindowClass) [...] |
InitWndProc | SetWindowLong(HWindow, GWL_WNDPROC, Longint(CreationControl.FObjectInstance)) |
TDockTree is an object that is associated with a TWinControl to allow it to provide docking to other controls (at least, I think that's what it does!) At any rate, it provides an example of an "approved" way to hook another control's messages. Here are the relevant pieces:
//-------------------------------------------------
constructor TDockTree.Create(DockSite: TWinControl);
//-------------------------------------------------
[...]
if not (csDesigning in DockSite.ComponentState) then
begin
FOldWndProc := FDockSite.WindowProc;
FDockSite.WindowProc := WindowProc;
end;
end;
//-------------------------------------------------
destructor TDockTree.Destroy;
//-------------------------------------------------
begin
if @FOldWndProc <> nil then
FDockSite.WindowProc := FOldWndProc;
[...]
inherited Destroy;
end;
//-------------------------------------------------
procedure TDockTree.WindowProc(var Message: TMessage);
//-------------------------------------------------
[... bunch of docking-related processing... then...]
FOldWndProc(Message);
end;
Go to: Drag and Drop Intro Page, or