You set the Parent
to be Form1.Panel2
, not Form1
itself. Your message handler will only receive messages that are posted to Form1
directly. Your other calls are posting to Form1.Handle
, which is why they work.
If you want to post the message to Parent.Handle
when Parent
is not Form1
, you will have to subclass the Panel you are assigning as Parent
:
type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
procedure FormCreate(Sender: TObject);
private
DefPanelWndProc: TWndMethod;
procedure PanelWndProc(var Msg: TMessage);
public
{ Public declarations }
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DefPanelWndProc := Panel2.WindowProc;
Panel2.WindowProc := PanelWndProc;
Form2 := TForm2.Create(Self);
Form2.Parent := Panel2;
Form2.BorderStyle := bsNone;
Form2.Show;
end;
procedure TForm1.PanelWndProc(var Msg: TMessage);
begin
if Msg.Msg = WM_FILEREADY then
ShowMessage('got event')
else
DefPanelWndProc(Msg);
end;
Otherwise, post the message to Form1
instead.
If you post using the Form1.Handle
property each time, everything will be fine (I am not counting multi-threaded code, as TWinControl.Handle
is not thread-safe). However, if you cache the value of Form1.Handle
to a variable and then post using that variable, your code will stop working if Form1.Handle
is recreated (which can and does happen). In that case, you need to detect the recreation and update the variable accordingly:
type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
procedure FormCreate(Sender: TObject);
protected
procedure CreateWnd; override;
procedure DestroyWnd; override;
private
procedure OnMyMessage(var Msg: TMessage); message WM_FILEREADY;
public
{ Public declarations }
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Form2 := TForm2.Create(Self);
Form2.Parent := Panel2;
Form2.BorderStyle := bsNone;
Form2.InnerHandle := Self.Handle;
Form2.Show;
end;
procedure TForm1.CreateWnd;
begin
inherited;
if Form2 <> nil then
Form2.InnerHandle := Self.Handle;
end;
procedure TForm1.DestroyWnd;
begin
if Form2 <> nil then
Form2.InnerHandle := 0;
inherited;
end;
procedure TForm1.OnMyMessage(var Msg: TMessage);
begin
ShowMessage('got event');
end;
Otherwise, don't use Form1.Handle
at all. Use a different window that will never be recreated.
You can use AllocateHWnd()
to create a dedicated window:
type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
MsgWnd: HWND;
procedure MsgWndProc(var Msg: TMessage);
public
{ Public declarations }
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
MsgWnd := AllocateHWnd(MsgWndProc);
Form2 := TForm2.Create(Self);
Form2.Parent := Panel2;
Form2.Borderstyle := bsNone;
Form2.InnerHandle := MsgWnd;
Form2.Show;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if MsgWnd <> 0 then
DeallocateHWnd(MsgWnd);
end;
procedure TForm1.MsgWndProc(var Msg: TMessage);
begin
if Msg.Msg = WM_FILEREADY then
ShowMessage('got event')
else
Message.Result := DefWindowProc(MsgWnd, Msg.Msg, Msg.WParam, Msg.LParam);
end;
Or you can use the Application.Handle
window:
type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
function AppWndProc(var Msg: TMessage): Boolean;
public
{ Public declarations }
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.HookMainWindow(AppWndProc);
Form2 := TForm2.Create(Self);
Form2.Parent := Panel2;
Form2.Borderstyle := bsNone;
Form2.InnerHandle := Application.Handle;
Form2.Show;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Application.UnhookMainWindow(AppWndProc);
end;
function TForm1.AppWndProc(var Msg: TMessage): Boolean:
begin
if Msg.Msg = WM_FILEREADY then
begin
ShowMessage('got event');
Result := True;
end else
Result := False;
end;