传递父句柄未到达的消息

时间:2016-08-07 07:06:03

标签: delphi windows-messages

在一个新项目中,我创建了一个包含2个面板的MainForm,以及一个带有按钮的Form。

我在MainForm上添加了这段代码:

interface

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    procedure FormCreate(Sender: TObject);
  private
     procedure OnMyMessage(var Msg: TMessage); message WM_FILEREADY;
  public
    { Public declarations }
  end;

implementation

uses
  PannelForm;

{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);
begin
  with TForm2.Create(self) do
  try
    parent := panel2;
    borderstyle := bsNone;
    InnerHandle := self.Handle;
    Show;

  finally

  end;
end;

procedure TForm1.OnMyMessage(var Msg: TMessage);
begin
  showmessage('got event');
end;

这个代码在Form上有一个按钮:

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    InnerHandle:HWND;
  end;

procedure TForm2.Button1Click(Sender: TObject);
begin
//  PostMessage(Application.Mainform.Handle, WM_FILEREADY, 0, 0); // works
//  PostMessage(Application.Handle, WM_FILEREADY, 0, 0); // not working
//  PostMessage(parent.Handle, WM_FILEREADY, 0, 0); // not working
  PostMessage(InnerHandle, WM_FILEREADY, 0, 0); // works

end;

我的问题是:在拨打第一个和第四个版本时,一切都很好。

第三个版本缺少什么?

为什么Parent不包含正确的句柄?是不是传递父母的(部分)点?

2 个答案:

答案 0 :(得分:2)

您已在TForm1中实施了邮件处理,但Form2.Parent.Handle不是Form1.Handle,而是已为其分配了Panel2.Handle

每个窗口控件都有自己的句柄。因此,您的面板具有与表单不同的句柄,并且它们无法处理在Form类中实现的消息。

尽管不是你所期望的,但一切都按预期工作。

答案 1 :(得分:1)

您将Parent设置为Form1.Panel2,而不是Form1。您的邮件处理程序将仅接收直接发布到Form1的邮件。您的其他来电正在发布到Form1.Handle,这就是他们工作的原因。

如果您希望在Parent.Handle不是Parent时将消息发布到Form1,则必须将您指定的小组子类化为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;

否则,请将邮件发送至Form1

如果每次都使用Form1.Handle属性发布,一切都会好的(我不计算多线程代码,因为TWinControl.Handle不是线程安全的)。但是,如果将Form1.Handle的值缓存到变量然后使用该变量发布,则如果重新创建Form1.Handle(可能并且确实发生),则代码将停止工作。在这种情况下,您需要检测重新创建并相应地更新变量:

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;

否则,根本不要使用Form1.Handle。使用永远不会重新创建的其他窗口。

您可以使用AllocateHWnd()创建专用窗口:

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;

或者您可以使用Application.Handle窗口:

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);     端;

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;