为什么弹出菜单显示时不调用Application.OnMessage?

Dmi*_*o25 8 delphi multithreading

我使用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;
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 8

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

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

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

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