2008. március 29., szombat
Intercepting Windows messages in non-visual components
Problem/Question/Abstract:
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. 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.
Component Download: http://www.delphidabbler.com/download.php?file=pjcbview.zip
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése