The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,262 other subscribers

Delphi processing all Windows messages

Posted by jpluimers on 2020/12/30

Since I had captures messages inside the main message loop, I forgot it is straightforward: create a [WayBackTApplicationEvents instance, then use the [WayBackOnMessage event and hook it to a method like

procedure TMainForm.ApplicationEventsMessage(var Msg: TMsg; var Handled: Boolean);
begin
  // figure out if the TMsg should be handled; set Handled to True if you do not want it to be processed by your application any further
  // if you do not handle it: bail out as quickly as possible
  // for performance reasons, it might be wise to have only the decision in this method, and all actual handling (including any managed variables) inside another method.
end;

Capturing these messages is limited to the ones processed through the main message loop (or message pump): these are the asynchronous ones either put there by PostMessage or related functions (like PostQuitMessage), or generated by Windows.

This means you will not see any synchronous messages sent to specific Windows using SendMessage.

Unlike the documentation for the OnMessage event, the type inside the method is TMsg from the unit  [WayBack]WinApi.Windows, which is an alias for the (documentation mentioned) tagMSG in the same unit; neither type is documented at docs.embarcadero.com or docwiki.embarcadero.com. Luckily, it is documented in the Windows SDK as the structure [WayBacktagMSG.

That structure is not the same as the [WayBackTMessage type inside the unit WinApi.Messages [WayBack], as TMessage omits these fields from TMsg:

  • HWND hwnd;
  • DWORD time;
  • POINT pt;
  • DWORD lPrivate;

Luckily the [WayBack] TMessageEvent (that describes the type of the signature of the event method) is better in this regard:

TMessageEvent = procedure (var Msg: TMsg; var Handled: Boolean) of object;

TMessageEvent includes the following parameters:

  • Msg identifies the Windows message that triggered the event.
  • Handled indicates whether the event handler responded to the message. If the event handler sets Handled to True, the application assumes that the message has been completely handled and halts any subsequent processing of the message.

TApplicationEvents is actually a multi-cast component (one of the very few multi-casting things parts of the Delphi VCL): an undocumented TMultiCaster class inside the unit Vcl.AppEvnts [WayBack].

A bit reminder though: ALL queued (not sent!) Windows messages flow through this method, so make it as short and efficient as possible, so from the OnMessage documentation:

OnMessage only receives messages that are posted to the message queue, not those sent directly with the Windows API SendMessage function.

Warning: Caution:Thousands of messages per second flow though this event. Be careful when coding the handler, because it can affect the performance of the entire application.
Tip: Call the CancelDispatch method from an OnMessage event handler to prevent the application from forwarding the event to any other application events objects.
It took until Delphi 2010 for the method [Archive.isTCustomApplicationEvents.CancelDispatch to be documented:
Prevents other TCustomApplicationEvents objects from receiving the current event.

A few more relevant links if you want to also hook SendMessage based messages:

–jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.