15
votes

The Delphi debugger is great for debugging linear code, where one function calls other functions in a predictable, linear manner, and we can step through the program line by line.

I find the debugger less useful when dealing with event driven gui code, where a single line of code can cause new events to be triggered, which may in turn trigger other events. In this situation, the 'step through the code' approach doesn't let me see everything that is going on.

The way I usually solve this is to 1) guess which events might be part of the problem, then 2) add breakpoints or logging to each of those events.

The problem is that this approach is haphazard and time consuming.

Is there a switch I can flick in the debugger to say 'log all gui events'? Or is there some code I can add to trap events, something like

procedure GuiEventCalled(ev:Event)
begin
    log(ev);
    ev.call();
end

The end result I'm looking for is something like this (for example):

FieldA.KeyDown 
FieldA.KeyPress 
FieldA.OnChange 
FieldA.OnExit 
FieldB.OnEnter

This would take all the guesswork out of Delphi gui debugging.

I am using Delphi 2010

[EDIT] A few answers suggested ways to intercept or log Windows messages. Others then pointed out that not all Delphi Events are Windows messages at all. I think it is these type of "Non Windows Message" Events that I was asking about; Events that are created by Delphi code. [/EDIT]

[EDIT2] After reading all the information here, I had an idea to use RTTI to dynamically intercept TNotifyEvents and log them to the Event Log in the Debugging window. This includes OnEnter, OnExit, OnChange, OnClick, OnMouseEnter, OnMouseLeave events. After a bit of hacking I got it to work pretty well, at least for my use (it doesn't log Key events, but that could be added). I've posted the code here

To use

  1. Download the EventInterceptor Unit and add it to your project
  2. Add the EventInterceptor Unit to the Uses clause
  3. Add this line somewhere in your code for each form you want to track.

    AddEventInterceptors(MyForm);

Open the debugger window and any events that are called will be logged to the Event Log

[/EDIT2]

7
Wayback link, at least Delphi 2005 is required.AmigoJack

7 Answers

9
votes

Use the "delphieventlogger" Unit I wrote download here. It's only one method call and is very easy to use. It logs all TNotifyEvents (e.g. OnChange, OnEnter, OnExit) to the Delphi Event Log in the debugger window.

3
votes

No, there's no generalized way to do this, because Delphi doesn't have any sort of "event type" that can be hooked in some way. An event handler is just a method reference, and it gets called like this:

if assigned(FEventHandler) then
  FEventHandler(self);

Just a normal method reference call. If you want to log all event handlers, you'll have to insert some call into each of them yourself.

3
votes

I know it is a little bit expensive, but you can use Automated QA's (now SmartBear) TestRecorder as an extension to TestComplete (if you want this only on your system, TestComplete alone will do). This piece of software will track your GUI actions and store it in a script like language. There is even a unit that can be linked into your exe to make these recordings directly at the user's system. This is especially helpful when some users are not able to explain what they have done to produce an error.

2
votes

Use WinSight to see the message flow in real time.

If you really want the program to produce a log, then override WinProc and/or intercept the messages in Application.

2
votes

The TApplication.OnMessage event can be used to catch messages that are posted to the main message queue. That is primarily for OS-issued messages, not internal VCL/RTL messages, which are usually dispatched to WndProc() methods directly. Not all VCL events are message-driven to begin with. There is no single solution to what you are looking for. You would have to use a combination of TApplication.OnMessage, TApplication.HookMainWindow(), WndProc() overrides, SetWindowsHook(), and selective breakpoints/hooks in code.

Borland's WinSight tool is not distributed anymore, but there are plenty of third-party tools readily available that do the same thing as WinSight, such as Microsoft's Spy++, WinSpector, etc, for tracking the logging window messages in real-time.

1
votes

As an alternative, to debug the triggered events use the debugger Step Into (F7) instead of Step Over (F8) commands.

The debugger will stop on any available code line reached during the call.

-1
votes

You can try one of the AOP frameworks for Delphi. MeAOP provides a default logger that you can use. It won't tell you what is going on inside an event handler but it will tell you when an event handler is called and when it returns.