Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Application.OnMessage is not called when popup menu is shown?

I use an Application.OnMessage event handler to process messages (notifications) from other threads in my program. And I found that if popup menu is active (opened), this event handler is not called. The test code is below (it is without threads but the principle is the same):

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;
like image 622
Dmitro25 Avatar asked Oct 26 '16 05:10

Dmitro25


1 Answers

OnMessage is called from the main thread's message loop. This message loop is implemented in Delphi's VCL library code. Hence this library code has the opportunity to call the event handler for OnMessage.

The popup menu is shown by calling the Win32 function TrackPopupMenuEx. This function implements a modal message loop to run the tracking UI for the menu. Because this message loop is implemented in Win32 code the VCL code does not have an opportunity to fire the OnMessage event. The Win32 code knows nothing of the VCL and runs a plain message loop. Messages are serviced and dispatched but no VCL specific code can be executed.

This is a perfect example of why PostThreadMessage should be avoided. Only if you control every message loop can it be used. Other points of failure include system message dialogs, drag and drop modal loops, window move/size modal loops.

You should stop using PostThreadMesaage. Instead create a window handle in the main thread using AllocateHWnd. Post messages to that window from your worker threads.

like image 142
David Heffernan Avatar answered Nov 07 '22 18:11

David Heffernan