我想记录delphi应用程序中引发的每个异常。为此,我在项目源代码中用自己的一个事件覆盖了Application.OException事件。
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-except块中捕获的异常。
当异常在exception块中被捕获时,它不会触发Application.OException事件。
有没有办法首先在Application.OException事件中捕获它,而不是在exception块中捕获它?
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中处理它。我避免使用一些第三方框架进行这种简单的日志记录。