2013-11-22 12 views
5

Ich habe einen globalen Ausnahme-Handler in Delphi eingerichtet. Bei einigen schweren Ausnahmen wird eine Fehlermeldung angezeigt (gefolgt von Halt()). Während die Fehlermeldung angezeigt wird, verarbeitet Delphi die Nachrichtenwarteschlange und verarbeitet Timer-Ereignisse, die zu weiteren Fehlern führen.Wie ignoriert man Timer-Ereignisse in Delphis MessageDlg

Was ich will, ist ein Fehlerdialog anzuzeigen, der Timer-Ereignisse nicht verarbeitet. Wie ist das in Delphi möglich?

Bearbeiten: Ich benutze Dialogs.MessageDlg (...), um die Nachricht anzuzeigen.

+0

Ich glaube, Sie einige globale Flag „Final Fehlermeldung angezeigt“ haben sollte und Intercept-App OnMsg, so dass nur Nachrichten an diesen Fehlerdialog angesprochen passieren würde, andere Nachrichten, die Sie herausfiltern würden http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Forms_TApplication_OnMessage.html –

+2

Wenn Sie 'TTimer' (s) verwenden, können Sie alle' rekursiv deaktivieren TTimer's (s) für die 'Application', bevor Sie den Dialog anzeigen. nur ein Gedanke. – kobik

+0

@ kobik Dann müsste meine globale Ausnahmebehandlungsroutine jeden TTimer kennen. Ich bevorzuge die anderen Lösungen. –

Antwort

4

Sie können Nachrichten in der Warteschlange filtern, wie WM_TIMER, mit TApplication.OnMessage.

procedure TMainForm.ApplicationMessage(var Msg: TMsg; var Handled: Boolean); 
begin 
    if ShowingFatalErrorDialog then 
    if Msg.Message = WM_TIMER then 
     Handled := True; 
end; 

Entweder das Ereignisbehandlungsroutine direkt zu Application.OnMessage zuweisen oder ein TApplicationEvents Objekt verwenden.

Offensichtlich müssen Sie die Implementierung für ShowingFatalErrorDialog bereitstellen, aber ich vertraue darauf, dass es für Sie offensichtlich ist, wie Sie dies tun.

+0

Ich dachte daran, die Nachrichten innerhalb des Dialogs zu filtern. Aber mit TApplicationEvents wird es so funktionieren, ohne auf globale vars angewiesen zu sein. Vielen Dank. –

+0

Ich denke, Black-List-Ansatz ist hier eine Sackgasse. Man sollte stattdessen Whitelist-Policy implementieren –

+0

@ Arioch'Die Sie beabsichtigten, diesen Kommentar auf die Frage, die ich denke, zu posten. –

2

versuchen, etwas wie folgt aus:

... 
    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; 
+0

Danke, ich habe Ihre Idee verwendet, um alle Ausnahmen in meiner endgültigen Implementierung zu verschlucken. Mein Hauptaugenmerk lag jedoch darauf, die fatalen Timer-Ereignisse nicht in der ersten Zeile zu generieren. –

+1

Ich denke, der 'FreeAndNil (E)' -Teil Ihres Codes ist falsch. Laut der Dokumentation, denke ich, sollten Sie die Ausnahme nicht freigeben. Dies führt zu einer [Zugriffsverletzung] (http://stackoverflow.com/q/22630972/2523663) für mich. Sehen Sie sich [diese Erklärung] an (http://stackoverflow.com/a/22668566/2523663). –

+0

Danke! Vielleicht kann 'ApplicationEvents.CancelDispatch' helfen, das AV zu verhindern, aber die Ausnahme nicht zu zerstören ist sicherlich viel besser! – NGLN

1

Nur als Referenz: Ich werde den folgenden Code verwenden, der eine Mischung aus beiden Antworten ist.

procedure SaveShowErrorMessage(...) 
begin 
    with TFatalErrorAppEvents.Create(nil) do //avoid timer and further exceptions 
    try 
     Dialogs.MessageDlg(...); 
    finally 
     Free; 
    end; 
end; 

Mit TFatalErrorAppEvents wie folgt:

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;