Trapping Windows Messages in Delphi

Written by Embarcadero USA on Posted in PROGRAMMING

 Technical Information Database

TI1487D.txt   Trapping Windows Messages in Delphi
Category   :General Programming
Platform    :All
Product    :Delphi  All

Description:
While Delphi provides many ways to trap the incoming messages
to VCL controls, you may require a quick and effective method
of "stealing" and replacing the windows procedure of a given 
window. The method presented here will effectively trap all 
Windows messages for any window or VCL control that has a 
Window handle property.

Background:
For every window that is created, a structure is created by the
system that holds information about the window. The information
contained in this structure includes, among other things, the
window's parent, instance information, and the address of the
window's main window procedure. It is through this procedure that
all Windows messages are sent for that window.

The Microsoft Windows API provides functions to both retrieve and
set the values contained in this structure, making it possible to
retrieve the address of a window's main procedure and reset that
address to point to a user installed function.

To replace the windows procedure, we will use the API function
SetWindowsLong(), and pass in the handle of the window we wish
to work with, the constant GWL_WNDPROC (telling the function
we wish to replace the windows procedure), and the address of
our function we wish to replace it with.

When we call the SetWindowsLong() function, it will return
the previous value we are replacing. We will want to remember
that value so we can call the original procedure for all the
messages we do not care to trap. We will also want to reinstall
the old procedure when we are done, so that message handling
returns to normal.

In our example code, we will trap the WM_VSCROLL message
of a TDbGrid component, giving us an indication that the
user has scrolled the vertical scroll bar. Since all
messages for the control are passed first through our
procedure, we can effectively trap and do processing for
any event before it is ever received by the component.

For a list of other notification messages you may be
interesed in trapping, you may search the Delphi's
Windows help file for messages starting with WM_.

Also note that the code has been written to compile
under both sixteen and thirty-two bit versions of Delphi.


unit WinProc1;

interface

uses
{$IFDEF WIN32}
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, DBGrids, DB, DBTables;
{$ELSE}
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
  Controls, Forms, Dialogs, DB, DBTables, Grids, DBGrids;
{$ENDIF}

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    Table1: TTable;
    DataSource1: TDataSource;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type
{$IFDEF WIN32}
  WParameter = LongInt;
{$ELSE}
  WParameter = Word;
{$ENDIF}
  LParameter = LongInt;

{Declare a variable to hold the window procedure we are replacing}
var
  OldWindowProc : Pointer;

function NewWindowProc(WindowHandle : hWnd;
                       TheMessage   : WParameter;
                       ParamW       : WParameter;
                       ParamL       : LParameter) : LongInt
{$IFDEF WIN32} stdcall; {$ELSE} ; export; {$ENDIF}
begin

{ Process the message of your choice here }
  if TheMessage = WM_VSCROLL then begin
    ShowMessage('The vertical scrollbar is scrolling!');
  end;

{ Exit here and return zero if you want     }
{ to stop further processing of the message }

{ Call the old Window procedure to }
{ allow processing of the message. }
  NewWindowProc := CallWindowProc(OldWindowProc,
                                  WindowHandle,
                                  TheMessage,
                                  ParamW,
                                  ParamL);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
{ Set the new window procedure for the control }
{ and remember the old window procedure.       }
  OldWindowProc := Pointer(SetWindowLong(DbGrid1.Handle,
                                         GWL_WNDPROC,
                                         LongInt(
NewWindowProc)));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
{ Set the window procedure back }
{ to the old window procedure.  }
  SetWindowLong(DbGrid1.Handle,
                GWL_WNDPROC,
                LongInt(OldWindowProc));

end;

end.


(*
{ The program's main source file }
program WinProc;

uses
  Forms,
  WinProc1 in 'WinProc1.pas' {Form1};

{$R *.RES}

begin
{$IFDEF WIN32}
  Application.Initialize;
{$ENDIF}
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
*)

{ end of ti }


Reference:


7/16/98 4:34:13 PM
 


Article originally contributed by

Tags: Delphi



Check out more tips and tricks in this development video: