Mega Code Archive

 
Categories / Delphi / System
 

Intercepting Windows messages in non visual components

Title: Intercepting Windows messages in non-visual components Question: Sometimes we need a non-windowed component (i.e. one that isn't derived from TWinControl) to receive Windows messages - but non-windowed component don't have window handles. For example suppose we are developing a non-visual component that registers our application as a clipboard viewer so the application can respond to changes in the clipboard (see article 575 for how to do this). To get information about clipboard changes our component needs to receive messages from Windows. Answer: The Delphi library function AllocateHWnd is used to create a hidden window for us and the related DeallocateHWnd disposes of the window when we've finished with it. The hidden window needs a window procedure. We can use a method of our component class to provide the window procedure. AllocateHWnd takes a reference to the method its parameter - it takes care of the problem of registering the method as a window procedure for us. In the method we handle the messages we are interested in and hand the rest off to Windows using the DefWindowProc API call. The following code gives the skeleton of how to use AllocateHWnd. First, here's the class declaration from the interface section of code: type // Our class derived from TComponent // (or another ancestor class) TMyClass = class(TComponent) private FHWnd: HWND; // field to store the window handle ... protected procedure WndMethod(var Msg: TMessage); virtual; // the window proc - called by Windows to handle // the given message ... public constructor Create(AOwner: TComponent); override; // create window proc here destructor Destroy; override; // free window proc here ... end; And here's the implementation details: TMyClass.Create(AOwner: TComponent); begin inherited Create(AOwner); ... // Create the window FHWnd := AllocateHWnd(WndMethod); ... end; TMyClass.Destroy; begin ... // Destroy the window DeallocateHWnd(FHWnd); ... inherited Destroy; end; TMyClass.WndMethod(var Msg : TMessage); var Handled: Boolean; begin // Assume we handle message Handled := True; case Msg.Msg of WM_SOMETHING: DoSomething; // Code to handle a message WM_SOMETHINGELSE: DoSomethingElse; // Code to handle another message ... else // We didn't handle message Handled := False; end; if Handled then // We handled message - record in message result Msg.Result := 0 else // We didn't handle message // pass to DefWindowProc and record result Msg.Result := DefWindowProc(FHWnd, Msg.Msg, Msg.WParam, Msg.LParam); end; Of course, we could just use the Windows API to create a window the hard way and provide a windows procedure. But it is more difficult to use a method (rather than a simple procedure) as a window procedure if we do it this way. The clever features about AllocateHWnd are that (a) it creates the hidden window for us and (b) it allows us to use a method, rather than a simple procedure as the window procedure -- and a method is more useful since it has access to the class's private data. An example clipboard viewer component is attached to this article.