我在Delphi中设置了一个全局异常处理程序。在某些严重的异常情况下会显示错误消息(随后是Halt())。当显示错误消息时,Delphi正在处理消息队列和处理定时器事件,这可能导致进一步的错误。
我的要求是显示一个错误对话框,该对话框不处理定时器事件。在Delphi中如何实现呢?
编辑:我使用Dialogs.MessageDlg(...)来显示消息。
我在Delphi中设置了一个全局异常处理程序。在某些严重的异常情况下会显示错误消息(随后是Halt())。当显示错误消息时,Delphi正在处理消息队列和处理定时器事件,这可能导致进一步的错误。
我的要求是显示一个错误对话框,该对话框不处理定时器事件。在Delphi中如何实现呢?
编辑:我使用Dialogs.MessageDlg(...)来显示消息。
TApplication.OnMessage
过滤排队的消息,例如WM_TIMER
。procedure TMainForm.ApplicationMessage(var Msg: TMsg; var Handled: Boolean);
begin
if ShowingFatalErrorDialog then
if Msg.Message = WM_TIMER then
Handled := True;
end;
可以直接将事件处理程序分配给Application.OnMessage
,也可以使用TApplicationEvents
对象。
显然,您需要提供ShowingFatalErrorDialog
的实现,但我相信您知道如何做到这一点。
尝试像这样做:
...
private
FAboutToTerminate: Boolean;
end;
...
type
ESevereError = class(Exception);
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Tag := Tag + 1;
if Tag > 2 then
raise ESevereError.Create('Error');
end;
procedure TForm1.ApplicationEvents1Exception(Sender: TObject;
E: Exception);
begin
if (E is ESevereError) and (not FAboutToTerminate) then
begin
FAboutToTerminate := True;
Application.ShowException(E);
Application.Terminate;
end;
end;
FreeAndNil(E)
部分是错误的。根据文档,我认为你不应该释放异常。这会导致我的程序出现了访问冲突。请看看这个解释。 - Alois HeimerApplicationEvents.CancelDispatch
可以帮助防止 AV,但是不破坏异常肯定是更好的选择! - NGLN仅供参考:我将使用以下代码,它是两个答案的混合。
procedure SaveShowErrorMessage(...)
begin
with TFatalErrorAppEvents.Create(nil) do //avoid timer and further exceptions
try
Dialogs.MessageDlg(...);
finally
Free;
end;
end;
type
TFatalErrorAppEvents = class(TApplicationEvents)
protected
procedure KillTimerMessages(var Msg: tagMSG; var Handled: Boolean);
procedure IgnoreAllExceptions(Sender: TObject; E: Exception);
public
constructor Create(AOwner: TComponent); override;
end;
constructor TFatalErrorAppEvents.Create(AOwner: TComponent);
begin
inherited;
OnMessage := KillTimerMessages;
OnException := IgnoreAllExceptions;
end;
procedure TFatalErrorAppEvents.IgnoreAllExceptions(Sender: TObject; E: Exception);
begin
//in case of an Exception do nothing here to ignore the exception
end;
procedure TFatalErrorAppEvents.KillTimerMessages(var Msg: tagMSG; var Handled: Boolean);
begin
if (Msg.message = WM_TIMER) then
Handled := True;
end;
TTimer
,在显示对话框之前,您可以递归禁用Application
中的所有TTimer
。这只是一个想法。 - kobik