为何在显示弹出菜单时未调用Application.OnMessage?

时间:2016-10-26 05:55:23

标签: multithreading delphi

我使用Application.OnMessage事件处理程序来处理程序中其他线程的消息(通知)。我发现如果弹出菜单处于活动状态(打开),则不会调用此事件处理程序。测试代码如下(它没有线程,但原理是相同的):

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := ApplicationEvents1Message;
end;

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if Msg.message = WM_USER then
    Beep();
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  PostThreadMessage(GetCurrentThreadId, WM_USER, 0, 0);
end;

1 个答案:

答案 0 :(得分:8)

从主线程的消息循环中调用

OnMessage。此消息循环在Delphi的VCL库代码中实现。因此,此库代码有机会调用OnMessage的事件处理程序。

通过调用Win32函数TrackPopupMenuEx显示弹出菜单。此函数实现模态消息循环以运行菜单的跟踪UI。因为此消息循环是在Win32代码中实现的,所以VCL代码没有机会触发OnMessage事件。 Win32代码对VCL一无所知,并运行简单的消息循环。消息被服务和分派,但是不能执行特定于VCL的代码。

这是为什么PostThreadMessage应该避免的完美例子。只有控制每个消息循环才能使用它。其他故障点包括系统消息对话框,拖放模态循环,窗口移动/大小模态循环。

您应该停止使用PostThreadMesaage。而是使用AllocateHWnd在主线程中创建一个窗口句柄。从工作线程向该窗口发布消息。