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
Download the EventInterceptor Unit and add it to your project
Add the EventInterceptor Unit to the Uses clause
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]
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.
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.
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.
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.
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.
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.
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.
Related
I'm wondering if it's possible to bypass the OutputDebugString? I'd like the OutputDebugString output showing up in DebugView and not in the internal Delphi Event Viewer window. But i can't find a way to tell Delphi not to swallow the OutputDebugString. Any ideas?
regards
That is not possible.
OutputDebugString sends string to debugger (as its name suggests). There can be only 1 active debugger per process. You run your application under Delphi - Delphi got the messages, since its a debugger. You run your application outside Delphi - DebugView can access them, since no debugger claimed it.
However: WHY do you need this? Just disable other types of events in Delphi event log - and you'll get the same functionality as DebugView has.
I think there is no way around this. The situation is still the same in Delphi 2009. You should submit a feature request: http://qc.embarcadero.com
I'm wondering what the advantage instead of Delphi's internal event log window should be?
Instead of DebugView you can try to use Process Monitor and its new "debug output" capability. It does not use OutputDebugString, it uses its own API, and there's also a Delphi wrapper here. You can use Process Monitor filtering features and Delphi won't trap that messages - but it's not a generic features as those of OutputDebugString.
Disabling "output messages" in the Event Log properties does not work?
Not what the original question asked, I realise, but it's worth taking a look at CodeSite from Raize Software. It takes OutputDebugString to a whole new level. Messages (can) get directed to a CodeSite viewer which is roughly equivalent to a highly souped up DebugView. Well worth every penny IMHO.
So I want to put a Breakpoint in a specific API or Windows message.
I don't find any easy way to do that without writing code in any Delphi version.
Is there a way to do that similar as I can put a breakpoint in memory access?
To stop at any call to an API function, find it in the implementation section of Windows.pas (or wherever the function of interest is declared) and set a breakpoint. That takes care of functions you use with load-time dynamic linking. For run-time dynamic linking (LoadLibrary and GetProcAddress), you'll need a different technique. The variable that gets the result of GetProcAddress will hold the address you want to break at, but I don't know off-hand how to set a breakpoint at that address.
Stopping on a Window message is trickier since messages can be retrieved in many places. You'll have to use conditional breakpoints instead.
To catch most posted messages, you can put a breakpoint in TApplication.HandleMessage on the first line after the call to PeekMessage. Set the condition to be Msg.Message = x. HandleMessage takes care of messages posted to the main thread's message queue for the main Application.Run message loop as well as the VCL's modal message loops. Other modal dialogs (such as Windows.MessageBox) won't use it, though.
Observing sent messages is harder because the OS dispatches them to their target window procedures directly. You'll have to set a breakpoint in the window procedure of every window class you're interested in. You could get most VCL window classes by putting your conditional breakpoint in Classes.StdWndProc.
Keep in mind that conditional breakpoints can be very slow. They work by the debugger putting an unconditional breakpoint there, and when the OS triggers it, the debugger takes over, checks the condition, and then resumes execution if the conditional fails. That can involve a lot of overhead, switching between the debugger and your application; programs receive lots of messages, so if you can find a way to avoid having the debugger interrupt your program to check every one of them, do it.
If this isn't feasible for whatever it is you're trying to debug, then I recommend posting a new question where you describe the problem you're really trying to solve.
You will need to go into Options | Linker and check "Debug DCUs". by default this is not checked so the debugger doesn't step through the entire VCL when you're trying to work.
A colleague and myself were debating over which way was less of a burden on the system resources. (Note: this is not the question I want an answer to. Rather the title and the line below in bold is the question I seek an answer for.)
1. Using KeyPreview to get the keypresses on a form.
or
2. Using defining an OnMessage procedure and handling it there.
At first glance it seems KeyPreview would be less of a system burden since defining an OnMessage procedure results in our program checking every message that comes in. Note messages we don't care about would cause it to jump out by the first if statement. That is at worst we would have an if statement executed for every message.
But we're wondering how Delphi deals with the KeyPreview property... We wonder if Delphi internally defines its own OnMessage and looks at the messages to then trigger the events that are related to keypresses.
If this is the case then would both approaches be about the same?
As others have already said - there is probably no noticeable difference.
I just wanted to point out an exellent article by Peter Below on that topic: A Key's Odyssey archive
This article describes the key message processing as implemented in Delphi 2007 for Win32 VCL forms applications. A few things have changed in this area compared with Delphi 7, but these are mostly additions that I will highlight when we get to them. Most of this code has survived basically unchanged since the times of Delphi 1, a tribute to the robustness of the design. If you are in a hurry or not interested in all the details you can refer to the outline in the summary for a condensed overview.
The KeyPreview functioning:
The KeyPreview property of the current active form is checked for the KeyUp-, KeyDown- and KeyPress- event handlers of the current active control. I.e.: a key press in any control results in the check of the form's KeyPreview property.
If that property is True, the event handler in question invokes the event handler of the form prior to that of itself. If the form's event handler does not change the key value to 0 (or #0, depending on KeyPress or KeyDown/KeyUp), then the active control's event handler takes back over, otherwise the event is considered handled.
Compared to Application.OnMessage:
So setting the key value to 0/#0 in a form's event handler is synonymous to setting the Handled parameter of Application.OnMessage. In this, there is virtually no difference. But since OnMessage is called very early in the dispatching process, there is a theoretical gain in performance because the message is not being dispatched any further. When you leave Handled to False, there is no difference at all, because the KeyPreview property is always checked, whether it is set or not.
The main difference that is left is that you have to set the KeyPreview of áll Forms to True, ánd implement and maintain for each of all forms the appropriate event handlers. Compare this to having just one event handler for Application.OnMessage. That is: assuming you could do with just one routine for all of your forms.
The best answer would be, measure it. Most likely neither one is going to place any noticeable "burden" on the system, and if you don't notice it when you're specifically looking for it, then your users won't either. So just go with whichever one's easier to understand in case you need to come back to that code sometime in the future.
The bottom line here is that you can't generate input quick enough to make the computer even notice. The computer would not be troubled if you produced input messages at rates hundreds or even thousands greater than you typically do.
You won't be able to measure the difference between handling something in OnMessage and using KeyPreview.
So the decision as to which to use comes down to which is most convenient. If you need handling to happen at an application wide level, and you don't have a common base class for all your forms, then you use OnMessage. If you want different behaviour for different forms then you need to use KeyPreview.
Personally I strongly recommend refactoring so that all forms in your projects derive from a common base (a subclass of TForm). This allows you much more flexibility. Done this way you can, for example, use the KeyPreview mechanism to apply intervention points for all forms in your applications.
As for how KeyPreview is implemented, the input messages get redirected in KeyDown, KeyPress etc. in TControl. To learn more read the source code.
I'm wondering if it's possible to bypass the OutputDebugString? I'd like the OutputDebugString output showing up in DebugView and not in the internal Delphi Event Viewer window. But i can't find a way to tell Delphi not to swallow the OutputDebugString. Any ideas?
regards
That is not possible.
OutputDebugString sends string to debugger (as its name suggests). There can be only 1 active debugger per process. You run your application under Delphi - Delphi got the messages, since its a debugger. You run your application outside Delphi - DebugView can access them, since no debugger claimed it.
However: WHY do you need this? Just disable other types of events in Delphi event log - and you'll get the same functionality as DebugView has.
I think there is no way around this. The situation is still the same in Delphi 2009. You should submit a feature request: http://qc.embarcadero.com
I'm wondering what the advantage instead of Delphi's internal event log window should be?
Instead of DebugView you can try to use Process Monitor and its new "debug output" capability. It does not use OutputDebugString, it uses its own API, and there's also a Delphi wrapper here. You can use Process Monitor filtering features and Delphi won't trap that messages - but it's not a generic features as those of OutputDebugString.
Disabling "output messages" in the Event Log properties does not work?
Not what the original question asked, I realise, but it's worth taking a look at CodeSite from Raize Software. It takes OutputDebugString to a whole new level. Messages (can) get directed to a CodeSite viewer which is roughly equivalent to a highly souped up DebugView. Well worth every penny IMHO.
The Application.ProcessMessages command is well known and I use it in long processes to ensure my program will not tie up the computer.
But I have one fairly quick set of processing, where I am buffering a view into a file. During the buffering procedure, a few system messages may get sent off (e.g. redraw or scrollbar move or other events). I want to prevent these from getting handled by ProcessMessages until my buffering is complete.
Is there any way to either:
Prevent Application.ProcessMessages until my procedure is complete, or
Trap all messages generated during my procedure, and not release them until the end of the procedure.
Allowing the ProcessMessages to continue even if it sends messages you don't want should not be classed as problematic. With a bit of code refactoring, you could move the buffering method into a separate thread and go from there.
If you are attempting to copy the "visual contents" of a control into a file,
look at the WM_PRINT(xxx) message which allows child controls to paint themselves into bitmaps
try the LockWindowUpdate Win32 API method call which will turn off all painting messages to that control
override the WndProc/DefaultWndProc method on your control class or even the parent class if you need to and simply return "true" for each message sent
override specific control methods (such as "scroll bar moved", "OnPaint", "OnPaintBackground" etc) on the control class or even the parent and simply do nothing if your buffering is in progress
Overriding the WndProc or DefaultWndProc and simply returning true for each message essentially "turns off" ProcessMessages but it's not safe to do it this way because the control might need to process one or more messages to function correctly.
Turning off ProcessMessages is not possible (without rewriting the VCL code for message processing) because of the fact that it's part of how the VCL form's message loop has been constructed.
Trap all messages generated during my procedure, and not release them
until the end of the procedure.
There is a dirty hack you can do (only if you can not come up with a better way):
You can watch (trap) any messages by using Win32 Hooks.
Specifically, use SetWindowsHookEx with WH_CALLWNDPROC as the idHook value.
You can then record them in a list/queue and resend them when you want.
I learned way back in Windows 2 that windows messages will happen at times you don't expect them. Any part of a library can cause your app's message processing to happen. Rather than hold back the tide, make your code robust against the situation. This may be as simple as usinga a BeginUpdate/EndUpdate pair, or more complex (using a temporary and doing the final update at the end).
At a pedantic level, the way you "prevent" Application.ProcessMessages is to not call any code that
shows a modal dialog
calls SendMessage
runs its own local message loop
calls Application.ProcessMessages (which is a local message loop)
If you write a loop that does nothing but numerical calculations and file I/O, your UI will be frozen until you exit the loop because no messages are being processed.
If you want your UI to be responsive during some long-running operation of unknown arbitrary code (third party library) but you don't want certain kinds of actions to occur in your app during that time, that's a different problem - that's about preventing reentrancy. You want to prevent some parts of your code from being used while a particular activity is in progress. For example, modal dialogs prevent you from interacting with the app windows underneath the dialog by disabling all the app's top level windows except the modal dialog itself.