Записать исключение в Delphi Application.OnException перед попыткой, кроме блока
Я хочу регистрировать каждое исключение, возникающее в приложении delphi. Для этого я переопределил событие Application.OnException одним из моих собственных в исходном коде проекта.
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.
Это работает отлично, но я не смог поймать с этим решением исключения, перехваченные в блоке try-exc.
Когда исключение перехватывается в блоке исключений, оно просто не вызывает событие Application.OnException.
Есть ли способ сначала перехватить его в событии Application.OnException, а не в блоке кроме?
2 ответа
Application.OnException
Обработчик вызывается только для необработанных исключений.
Необработанное исключение - это то, где нет try..except
Блок поймал исключение или где он был пойман и затем повторно поднят.
Используя несколько тривиальных примеров, давайте предположим, что это практически единственный код в приложении и что нет других обработчиков исключений...
try
a := 42 / 0;
except
on EDivisionByZero do
begin
Log.i('Silly division by zero error has been logged');
raise;
end;
end;
В этом случае исключение перехватывается, но у приложения нет стратегии обработки исключения, поэтому просто регистрирует, что оно произошло, и затем повторно вызывает исключение. Выполнение будет продолжено в любом внешнем except
блок. Если их нет, или если что-то может существовать, повторно вызовите исключение, то в конечном итоге исключение достигнет Application.OnException
обработчик.
Но обработчику исключений может не потребоваться повторно вызывать исключение:
try
a := 42 / 0;
except
on EDivisionByZero do
a := 0;
end;
В этом случае обработчик исключений обрабатывает деление на ноль и не вызывает его повторно, поскольку в этом случае код с радостью продолжит работу с нулевым результатом (маловероятно, но это только пример).
Поскольку исключение не вызывается повторно, выполнение продолжается (послеtry..except
блок), как будто исключение никогда не случалось в первую очередь. ВашApplication.OnException
никогда не узнает об этом.
В итоге:Application.OnException
вашпоследний шанс разобраться с необработанным исключением. Это не первая возможность ответить на любое исключение.
Перехват исключений в момент их возникновения до того, как какой-либо код приложения будет иметь возможность реагировать или иметь дело с ними, возможен, но это довольно сложный процесс, и простой механизм не предоставляется "из коробки".
К счастью, вы можете использовать сторонние библиотеки, которые могут предоставить возможности, которые вы хотите внедрить в свое приложение.
Популярным для Delphi, который вы можетепопробовать, является madExcept.
Я наконец использовал JCL для захвата и регистрации всех моих исключений. Я создал новый файл.pas со следующим кодом:
/// <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.
С помощью этого кода я могу перехватить исключение и обработать его в моей функции SetExceptionError. Я избегал использования каких-либо сторонних фреймворков для этой простой регистрации.