madExcept Internals 

www.madshi.net

When talking about the internals of madExcept, we should split it all into 3 pieces, which are:

1. Your just linked binary gets patched by madExcept.
2. When your module (application or dll) initializes, madExcept hacks into Delphi's exception logic.
3. When an exception occurs, madExcept creates an extensive bug report and notifies all registered exception handlers.

Now let's look at those 3 pieces in detail:

Inside of the IDE...

One part of madExcept is a little wizard (named "madExceptWizard"), which integrates itself into the Delphi IDE in several aspects:

1. The menu item "madExcept settings..." is added to the "Project" menu. This menu item opens a settings dialog with which you can configure madExcept's settings for the current project, including the layout of the exception box, your email address and much more. The settings are saved per project in the text file "projectName.mes" in the project's root folder.
2. The menu item "madExcept configuration..." is added to the "Tools" menu. This menu item opens just another settings dialog. The settings in this dialog are project independent. E.g. you can configure whether you want madExcept to catch Delphi/BCB IDE exceptions, or whether madExcept may modify your projects according to its own needs. These global settings are stored in the registry.
3. Whenever you open, close or save a project, madExcept's Delphi wizard gets notified and then automatically also opens, closes or saves the madExcept settings for the current project.
4. If you enable/disable madExcept support for your project, the wizard automatically adds/deletes the unit "madExcept" (and maybe more units, depending of your settings) to/from your project's uses clause.
5. Finally, the wizard gets notified, when a project was just being linked. In that very moment the wizard opens the fresh binary and patches it. The madExcept settings (like button captions etc) are written into the binary. Furthermore the map file is compressed, encrypted and then attached to the binary as a resource.

If you're not using the Delphi IDE to build your projects, but the command line tools instead, you should look at the tool "madExceptPatch.exe", that is shipped with the madExcept package. This tool can do the same things as the IDE wizard.

When initializing...

When your application gets started or when your DLL gets loaded, madExcept hooks deep into Delphi's system units including "System.pas" and "SysUtils.pas". The usual exception event handlers ("TApplication.OnException" and "System.ErrorProc") are hacked, you can set them to any value without effect. Furthermore several additional functions are intercepted. "SysUtils.ShowException", "TApplication.ShowException" and "TApplication.HandleException" are all diverted to madExcept's internal exception handling.

Normally when an exception occurs during the initialization part of any unit, you will not see a senseful exception box, but instead something like "runtime error 216". Furthermore such initialization errors normally don't run through any of the exception handling callbacks. With madExcept the initialization errors behave exactly like other exceptions, also the cryptic messages should no longer appear.

At the end of the initialization madExcept creates two threads, one is responsible for regularly checking whether the main thread is frozen. The other one sleeps. It will later do all the work when an exception occurs.

Handling exceptions...

In the moment when an exception is to be handled, madExcept notifies the exception handling thread, which was created during the initialization (see above). The exception handling thread takes over control. It collects some basic information about the currently running system like OS information, consumed resources and so on.

Now it is time to call all registered event handlers (see RegisterExceptionHandler). If a handler is meant to be "synchronized", the event handler is called in the context of the main thread. Otherwise the main thread is left alone and the handler is called directly in the context of the exception handling thread.

All registered exception handlers are called in a row, until one handler sets the flag handled to true. In that case the whole exception handling is aborted and the exception handling thread goes back to sleep, waiting for the next exception.

If no handler sets the mentioned flag, the exception handling thread shows the exception box, while in another newly created helper thread some time consuming tasks are done like analyzing the exception, calculating all threads' callstacks etc. As the helper thread finishes to calculate all wanted information, the exception box is updated to show the latest information.