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 [WayBack] TApplicationEvents
instance, then use the [WayBack] OnMessage
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 [WayBack] tagMSG
.
That structure is not the same as the [WayBack] TMessage
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 setsHandled
toTrue
, 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 APISendMessage
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 theCancelDispatch
method from anOnMessage
event handler to prevent the application from forwarding the event to any other application events objects.
TCustomApplicationEvents.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:
- [WayBack] delphi – Let form catch all messages – Stack Overflow
- [WayBack] delphi – How do I catch certain events of a form from outside the form? – Stack Overflow
- [WayBack] Trapping Windows Messages in Delphi – Embarcadero Community
- Technical Information Database
- TI1487D.txt
- Trapping Windows Messages in Delphi
- Category :General Programming
- Platform :All
- Product :Delphi All
- Description: While Delphi provides many ways to trap the incoming messages to VCL controls, you may require a quick and effective method of…
- [WayBack] Handling Messages | Adventures in Delphi 6 Messaging | InformIT
As a Delphi component developer, you have to directly handle many Windows messages and then invoke events corresponding to those messages. Xavier Pacheco and Steve Teixeira discuss how the Windows message system works.
- [WayBack] Intercept Windows Messages … all or one by one – delphi
- [WayBack] Capture All Windows messages
How can I catch all Windows messages? For example , my active window is Microsoft Word and when I click on it I want to catch this message with my DELPHI program, which is not active in this moment.
The answer describes using [WayBack] SetWindowsHookExA function | Microsoft Docs.
An alternative is to overwrite the WndProc of TComponent instances. For both you need to have the window handles of all components first.
- [WayBack] how to list all windows Messages???!! – Delphi Pages Forums which has a unit that can hook messages for the main window based on:
- [WayBack] Handling Windows Messages the Delphi way
- [WayBack] SendMessage, PostMessage, and Related Functions – Windows applications | Microsoft Docs
- Overwriting (and saving for later restore!) the [WayBack]
TControl.WindowProc
of any control: [WayBack] delphi – How do I catch certain events of a form from outside the form? – Stack Overflow - [WayBack] projects/Hooks.pas at master · hypfvieh/projects · GitHub
–jeroen
Leave a comment