4

This is a follow-up question.

My prior questions:

My problem:

TComponent doesn't own a window handle like TWinControl. I don't want to rely on an external one.

This is a snippet of my custom component

type
  TMyClipBoardListener = class(TComponent)
  private
    FInnerWindowHandle: HWnd;
    FNextHWnd:  HWnd;
    //...
  protected
    procedure Loaded; override;
    procedure WndProc(var Msg: TMessage); // <<< This is my wouldbe Window to handle messages
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    // ...
  published
    // ...
  end;

Implementation excerpt of my custom component

constructor TMyClipBoardListener .Create(AOwner: TComponent);
begin
  inherited;
  //
  FInnerWindowHandle := ...; // <<< What to do here ? Should I pass it to a function/procedure I missed?
end;

destructor TMyClipBoardListener .Destroy;
begin
  if not(csDesigning in ComponentState) then
  begin
    ChangeClipboardChain(FInnerWindowHandle, FNextHWnd);
  end;
  //
  // <<< Are there some cleaning code related to FInnerWindowHandle to implement here or elsewhereCreates a window that implements a specified window procedure. ?
  //
  inherited;
end;

procedure TMyClipBoardListener.Loaded;
begin
  inherited;
  //
  if not(csDesigning in ComponentState) then
  begin
    FNextHWnd:= SetClipboardViewer(FInnerWindowHandle);
  end;
end;

procedure TMyClipBoardListener.WndProc(var Msg: TMessage);
begin
  with Msg do
  begin
    // Message to handle : WM_CHANGECBCHAIN and WM_DRAWCLIPBOARD
    // ... 
    else
      Result := DefWindowProc(FInnerWindowHandle, Msg, WParam, LParam); // <<< Is this the right way to do default handling properly?
  end;
end;

My question:

How can I get for my custom component an inner window implementing the embedded window procedure?

Community
  • 1
  • 1
menjaraz
  • 7,551
  • 4
  • 41
  • 81
  • Then the component needs to have a parent, @David. And if it's placed on a form at design time, it will have a size and location that don't mean anything. – Rob Kennedy Jan 11 '12 at 17:48
  • I don't see the value in linking to your previous questions in this case. – Warren P Jan 11 '12 at 23:35
  • @Warren P: I am planning to write an advanced clipboard monitoring (custom) component. Maybe it's not yet time to link them as you point out, but later I will have to put all together. More posts related to that will come. – menjaraz Jan 12 '12 at 04:03

1 Answers1

12

Call AllocateHwnd from the Classes unit (not Forms).

FInnerWindowHandle := AllocateHwnd(WndProc);

When you're finished, call DeallocateHwnd.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 2
    +1 Gah, I can't believe that [today](http://stackoverflow.com/questions/8820294/how-can-i-safely-use-the-ttimer-component-from-a-background-thread), of all days, I didn't think of that! – David Heffernan Jan 11 '12 at 17:55
  • because Forms do not have any `AllocateHwnd`? – OnTheFly Jan 11 '12 at 20:56
  • 1
    @User, AllocateHwnd originally lived in *Forms*. It has since been moved to *Classes*. There are some Delphi versions released during the transition where it lives in *both* units, but the *Forms* copy is marked *deprecated*. If you have a version in *Classes*, then use it. If your Delphi version is too old to have that, then use the one in *Forms*. – Rob Kennedy Jan 11 '12 at 21:17