问题摘要:中的某些代码UartComm.OnGetIdRES()
引发ERangeError
,使我的程序崩溃。这个错误不是问题,重要的是为什么我的应用程序全局异常钩子捕获异常,但是我的程序仍然崩溃。我希望钩子能够捕获并处理所有未处理的异常;该程序应继续运行。
这是负责全局异常挂钩的单元:
unit LogExceptions;
interface
uses
Windows, SysUtils, Classes, JclDebug, JclHookExcept;
procedure AppendToLog(Msg: String; const LogFileLevel: TLogFileLevel);
implementation
uses Main;
procedure HookGlobalException(ExceptObj: TObject; ExceptAddr: Pointer;
OSException: Boolean);
var
Trace: TStringList;
DlgErrMsg: String;
begin
{ Write stack trace to `error.log`. }
Trace := TStringList.Create;
try
Trace.Add(
Format('{ Original Exception - %s }', [Exception(ExceptObj).Message]));
JclLastExceptStackListToStrings(Trace, False, True, True, False);
Trace.Add('{ _______End of the exception stact trace block_______ }');
Trace.Add(' ');
Trace.LineBreak := sLineBreak;
LogExceptions.AppendToLog(Trace.Text, lflError);
{ Show an dialog to the user to let them know an error occured. }
DlgErrMsg := Trace[0] + sLineBreak +
Trace[1] + sLineBreak +
sLineBreak +
'An error has occured. Please check "error.log" for the full stack trace.';
frmMain.ShowErrDlg(DlgErrMsg);
finally
Trace.Free;
end;
end;
procedure AppendToLog(Msg: String; const LogFileLevel: TLogFileLevel);
{ .... irrelevant code ....}
initialization
Include(JclStackTrackingOptions, stTraceAllExceptions);
Include(JclStackTrackingOptions, stRawMode);
// Initialize Exception tracking
JclStartExceptionTracking;
JclAddExceptNotifier(HookGlobalException, npFirstChain);
JclHookExceptions;
finalization
JclUnhookExceptions;
JclStopExceptionTracking;
end.
(如果它是有帮助这里的链接JclDebug.pas
和JclHookExcept.pas
)
我要做的所有激活钩子的操作就是将添加LogExceptions
到中的interface uses
列表中Main.pas
。
现在,这是崩溃的分步说明:
UartComm.OnGetIdRES()
ERangeError
当我尝试设置提高Length
动态数组的-7
:
SetLength(InfoBytes, InfoLength);
我们进入LogExceptions.HookGlobalException()
。此时在IDE中显示的调用堆栈是这样的(我遗漏了内存地址):
-> LogExceptions.HookGlobalException
:TNotifierItem.DoNotify
:DoExceptNotify
:HookedRaiseException
:DynArraySetLength
:DynArraySetLength
:@DynArraySetLength
UartComm.TfrmUartComm.OnSpecificRES // This method runs `OnGetIdRES()`
UartComm.TfrmUartComm.OnSpecificPktRX
UartComm.TfrmUartComm.DisplayUartFrame
UartComm.TfrmUartComm.UartVaComm1RxChar
VaComm.TVaCustommComm.HandleDataEvent
VaComm.TVaCommEventThread.DoEvent
{ ... }
{ ... Some low-level calls here .... }
我们一离开HookGlobalException
调试器,就会抛出一个对话框:
引发带有消息“范围检查错误”的异常类ERangeError
如果我按“继续”,程序仍处于冻结状态。如果没有调试器,程序此时将冻结。
如果单击“中断”并继续使用调试器,则执行过程将一直贯穿整个堆栈VaComm.TVaCommEventThread.DoEvent
并执行以下行:
Application.HandleException(Self);
之后,它什么也不做(我进入调试器例程,并且程序永远“运行”)。
即使我不对钩子使用JCL库,而是指向Application.OnException
一些空例程,也会发生完全相同的事情。
为什么异常被钩子捕获,然后在钩子返回时重新引发?我如何抑制该异常,以使程序不会崩溃却可以继续运行?
更新:我取得了3个重大发现:
GlobalExceptHook()
在异常降到调用堆栈之前。Application.OnException
在代码中的其他位置被重新分配。Application.HandleException
执行OnException
(但是调试器没有向我显示,当我尝试进入内部时),那里有一行试图关闭COM端口。这是使我的程序的GUI冻结的那一行。当我弄清楚一切后,我会写一个答案。
问题是UartComm.TfrmUartComm.UartVaComm1RxChar
事件触发了。在此例程中引发未处理的异常时,执行将通过调用堆栈进行处理,直到到达为止Application.OnException
。
在内部,OnException
我尝试使用来关闭COM端口VaComm1.Close()
。其中一部分Close()
是调用以停止VaComm1
线程并WaitFor()
完成线程。但是请记住,UartVaComm1RxChar
永不归来!永不完结!因此,这WaitFor()
一直在等待。
解决方案是启用TTimer
内部OnException
并将VaComm1.Close()
例程移到此Timer中。程序完成了对引发的异常的处理,并在事件完成后返回执行“ main”循环。现在,TTimer触发并关闭COM端口。
更多细节在这里。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句