Board index » delphi » Having a TComponent Capture WM_CLOSE

Having a TComponent Capture WM_CLOSE

G'day,

I'm trying to get a TComponent descendant to capture a WM_CLOSE message
for the form it's been placed on.  I've used AllocatedHWnd to create a
hidden utility window, but the only messages I seem to be capturing is
WM_ACTIVATEAPP and WM_DESTROY.   By the time I get WM_DESTROY it's to
late, and the WM_ACTIVATEAPP is just Delphi receiving focus.

If anyone could shed light on this I'd be grateful.  I'm trying to
create a component that remembers the Form Position.  Yes I know there's
third party components out there, but they don't do all that I want them
to.

Cheers

Mike  

 

Re:Having a TComponent Capture WM_CLOSE


Mike,
Can you explain in simple language what you are trying to achieve???

Any component owned by a form CAN get its Position property simply by:

        SavedPosition := (MyComponent.Owner as TForm).Position;

As for the WM_CLOSE capture just override the OnClose event for the
component.

If however you are trying to capture the WM_CLOSE for the form inside a
component that
belongs to the form - well, you are in a lot of trouble then.
It cannot be done in a straightforward manner.

However, if you explain  *WHY* you want to do this, I (somebody) might be
able to help with
a different approach.

Alek.

Quote
Mike Thompson wrote in message ...
>G'day,

>I'm trying to get a TComponent descendant to capture a WM_CLOSE message
>for the form it's been placed on.  I've used AllocatedHWnd to create a
>hidden utility window, but the only messages I seem to be capturing is
>WM_ACTIVATEAPP and WM_DESTROY.   By the time I get WM_DESTROY it's to
>late, and the WM_ACTIVATEAPP is just Delphi receiving focus.

>If anyone could shed light on this I'd be grateful.  I'm trying to
>create a component that remembers the Form Position.  Yes I know there's
>third party components out there, but they don't do all that I want them
>to.

>Cheers

>Mike

Re:Having a TComponent Capture WM_CLOSE


Mike,

you need to subclass the form the API way to get at messages it receives
from a component. Attached is a unit Rick Rogers posted some time ago
on the subject.

Peter Below (TeamB)  100113.1...@compuserve.com)

unit FTSubCls;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Controls, Forms;

type

  TFTSubclassWnd = class(TComponent)
  private
    { Private property storage }
    FNewWndProcPtr : TFarProc;
    FOldWndProcPtr : TFarProc;
    FWindowHandle : HWnd;
  protected
    { Virtual methods for descendants }
    procedure NewWndProc(var Message: TMessage); virtual; abstract;
    procedure AssignHandle; virtual;
    { Component methods }
    procedure ReplaceWndProc;
    procedure RestoreWndProc;
    procedure CallOldWndProc(var Message: TMessage);
    { Protected properties }
    property NewWndProcPtr: TFarProc read FNewWndProcPtr;
    property OldWndProcPtr: TFarProc read FOldWndProcPtr;
    property WindowHandle: HWnd read FWindowHandle;
  public
    { Construction/destruction }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

constructor TFTSubclassWnd.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  if not (AOwner is TForm) then raise Exception.Create('Owner must be
form');
  AssignHandle;
  ReplaceWndProc;
end;

destructor TFTSubclassWnd.Destroy;
begin
  RestoreWndProc;
  inherited Destroy;
end;

procedure TFTSubclassWnd.CallOldWndProc(var Message: TMessage);
begin
  with Message do
    Result := CallWindowProc(FOldWndProcPtr, FWindowHandle, Msg, wParam,
lParam);
end;

procedure TFTSubclassWnd.AssignHandle;
begin
  with (Owner as TForm) do
  begin
    { Ensure the window handle has been allocated }
    HandleNeeded;
    { Assign window handle (with special processing for MDI parent forms }
    if (FormStyle = fsMDIForm)
      then FWindowHandle := ClientHandle
      else FWindowHandle := Handle;
  end;
end;

procedure TFTSubclassWnd.ReplaceWndProc;
begin
  { Save pointer to old WndProc }
  FOldWndProcPtr := Pointer(GetWindowLong(FWindowHandle, GWL_WNDPROC));
  { Create pointer to NewWndProc }
  FNewWndProcPtr := MakeObjectInstance(NewWndProc);
  if (FNewWndProcPtr = nil) then
    raise EOutOfResources.Create('Cannot allocate WndProc handle');
  { Subclass window by setting GWL_WNDPROC to NewWndProc }
  SetWindowLong(FWindowHandle, GWL_WNDPROC, LongInt(FNewWndProcPtr));
end;

procedure TFTSubclassWnd.RestoreWndProc;
begin
  SetWindowLong(FWindowHandle, GWL_WNDPROC, LongInt(FOldWndProcPtr));
  if FNewWndProcPtr <> nil then FreeObjectInstance(FNewWndProcPtr);
end;

end.
<<<<

You'll need to descend any components which need to "listen" to the form's
messages from the TSubclassWnd
component. In your descendant component, you'll need to override the
NewWndProc procedure, and provide a
message handler that looks for messages of interest. For example, your
procedure will look something like this:

procedure TMaleyComponent.NewWndProc(var Message: TMessage);
begin
  if (Message.Msg = WM_SIZE) then { Do something };
end;

Other Threads