Capture exception in Delphi Application.OnException before try except block

3.2k Views Asked by At

I want to log every exception raised in the delphi application. For that, I overrided the Application.OnException event with one of my own in the project source code.

program Project;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Logger in 'Logger.pas',
  JCLDebugHandler in 'JCLDebugHandler.pas';

{$R *.res}

begin
   Application.Initialize;
   Application.OnException := TApplicationException.AppException;
   Application.MainFormOnTaskbar := True;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
end.

This works perfectly, but I´m failing at catching with this solution the exceptions catched in a try-except block.

When the exception is catched in the except block, it just not triggers the Application.OnException event.

Is there any way to first catch it in the Application.OnException event rather than the except block?

2

There are 2 best solutions below

0
On

The Application.OnException handler is only called for unhandled exceptions.

An unhandled exception is one where no try..except block has caught the exception or where it has been caught and then re-raised.

Using some trivial examples to demonstrate, let's assume that this is virtually the only code in the application and that there are no other exception handlers...

try
  a := 42 / 0;
except
  on EDivisionByZero do
  begin
    Log.i('Silly division by zero error has been logged');
    raise;
  end;
end;

In this case, the exception is caught but the application has no strategy for handling the exception so simply logs that it has occurred and then re-raises the exception. Execution will continue in any outer except block. If there are none, or if any that may exist also re-raise the exception, then eventually the exception will reach the Application.OnException handler.

But an exception handler might not need to re-raise an exception:

try
  a := 42 / 0;
except
  on EDivisionByZero do
    a := 0;
end;

In this case, the exception handler handles the division by zero and does not re-raise it since the code is happy to proceed with a result of zero in that case (unlikely, but this is just an example).

Since the exception is not re-raised, execution proceeds (after the try..except block) as if the exception had never happened in the first place. Your Application.OnException will never know about it.

In summary: Application.OnException is your last chance to deal with an unhandled exception. It is not the first opportunity to respond to any exception.

Intercepting exceptions at the moment that they occur, before any application code has had an opportunity to react or deal with them is possible, but is pretty advanced stuff and no simple mechanism is provided "out of the box".

Fortunately there are 3rd party libraries you can use that may provide the capabilities you are seeking to introduce into your application.

A popular one for Delphi which you might wish to check out is madExcept.

0
On

I finally used JCL for capturing and logging all my exceptions. I created a new .pas file with the following code:

/// <summary>
/// Inicializa JCL para capturar la informacion necesaria de la excepcion.
/// </summary>
initialization
   JclAddExceptNotifier(SetExceptionError);
   JclStackTrackingOptions := JclStackTrackingOptions + [stExceptFrame];
   JclStartExceptionTracking;

/// <summary>
/// Finaliza la notificacion de JCL luego de capturar la informacion necesaria de la excepcion.
/// </summary>
finalization
   JclRemoveExceptNotifier(SetExceptionError);
end.

With this code, I can capture the exception and treat it in my function SetExceptionError. I was avoiding using some 3rd party framework for this simple logging.