0
votes

I've created an class that should propagate to the entire application a customized message when its going to be freed. I did it with PostMessage and it worked with few bugs

PostMessage(Application.Handle, UM_MYMESSAGE, 0, 0);

then I realized it should be synchronous - via SendMessage.

SendMessage(Application.Handle, UM_MYMESSAGE, 0, 0);

On my Form I was handling the messages with a TApplicationEvents component, but just switching SendMessage to PostMessage didn't make it handle the message

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if Msg.message = UM_MYMESSAGE then
  begin
    ShowMessage('Ok');

    Handled := True;
  end;
end;

It works if I pass the Form Handle but not working with Application.Handle... What am I doing wrong?

1
As you've found out, ApplicationEvents can only expose posted messages. You might have as well hit F1 on OnMessage to confirm. - Sertac Akyuz
thanks for the light.. can You help me on how to handle the message then? - luix10
I don't understand what entire application means, so hard to comment. Perhaps you can use "broadcast", or install a hook, or loop through forms - or explain your problem in more detail. - Sertac Akyuz
I think you are making a mistake by forcing this through the application window handle, or even via a message at all. Just call a function directly. - David Heffernan
I've no idea what you are talking about - David Heffernan

1 Answers

6
votes

The TApplication(Events).OnMessage event is triggered only for messages that are posted to the main UI thread message queue. Sent messages go directly to the target window's message procedure, bypassing the message queue. That is why your OnMessage event handler works with using PostMessage() but not SendMessage().

To catch messages that are sent to the TApplication window, you need to use TApplication.HookMainWindow() instead of TApplication(Events).OnMessage, eg:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.HookMainWindow(MyAppHook);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Application.UnhookMainWindow(MyAppHook);
end;

function TForm1.MyAppHook(var Message: TMessage): Boolean;
begin
  if Message.Msg = UM_MYMESSAGE then
  begin
    ShowMessage('Ok');
    Result := True;
  end else
    Result := False;
end;

That being said, a better solution is to use AllocateHWnd() to create your own private window that you can post/send your custom messages to, eg:

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyWnd := AllocateHWnd(MyWndMsgProc);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DeallocateHWnd(FMyWnd);
end;

procedure TForm1.MyWndMsgProc(var Message: TMessage);
begin
  if Message.Msg = UM_MYMESSAGE then
  begin
    ShowMessage('Ok');
    Message.Result := 0;
  end else
    Message.Result := DefWindowProc(FMyWnd, Message.Msg, Message.WParam, Message.LParam);
end;

Then you can post/send messages to FMyWnd.