|   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  ![]()