2010-08-05 2 views
6

Wir haben eine nicht verwaltete C++ - Anwendung, die APIs von Drittanbietern zum Lesen von CAD-Dateien verwendet. Bei bestimmten beschädigten CAD-Dateien stürzt die 3rd-Party-Bibliothek ab und bringt unsere EXE-Datei herunter. Aus diesem Grund ist unsere Hauptanwendung eine separate EXE und wird dadurch nicht vom Absturz betroffen. Wir haben jedoch ärgerliche Microsoft-Fehlerberichterstellungsdialoge.Kann man die Microsoft-Fehlerberichterstattung für eine einzelne App verhindern?

Ich möchte das Microsoft Error Reporting systemweit nicht deaktivieren. Gibt es eine Möglichkeit, die Fehlerberichterstattung für eine einzelne Anwendung zu deaktivieren, so dass im Falle eines Absturzes das System ohne Fehlermeldung automatisch stürzt?

Antwort

0

Ich bin überhaupt nicht sicher, aber vielleicht SetErrorMode oder SetThreadErrorMode wird für Sie arbeiten?

+0

Zusätzlicher Hinweis, wenn dieser Absturz durch eine nicht behandelte strukturierte Ausnahme (Zugriffsverletzung, Stapelüberlauf, etc.) verursacht wird Vielleicht möchten Sie sich mit strukturierten Ausnahmehandlern beschäftigen. Sie könnten sie verwenden, um einige Informationen zu protokollieren und im stillen Absturz oder was auch immer Sie sonst tun möchten. –

5

Unter Vista und höher kann die API-Funktion WerAddExcludedApplication verwendet werden, um eine angegebene ausführbare Anwendung von der Fehlerberichterstattung auszuschließen. Soweit mir bekannt ist, gibt es keine ähnliche Option für XP und andere ältere Betriebssystemversionen.

Da WER jedoch nur auf nicht behandelte Anwendungsausnahmen zugreifen wird, sollten Sie in der Lage sein, dies zu unterdrücken, indem Sie Ihrer EXE einen "Catch-All" -Ausnahmehandler hinzufügen. Für einige Ideen, wie das zu erreichen ist, siehe vectored exception handling.

Beachten Sie, dass alle unbehandelten Ausnahmen unterdrückt ist generell eine schlechte Idee (und wird zum Beispiel dazu führen, dass App Windows-Logo-Zertifizierung zum Scheitern verurteilt), so dass man diese Technik nicht wahllos verwenden sollte ...

+0

+1 für die Erwähnung der WER-API. – bk1e

5

Ja, es gibt etwas, was du tun kannst. Rufen Sie SetUnhandledExceptionFilter() in Ihrer main() -Methode auf, um einen Rückruf zu registrieren. Es wird aufgerufen, wenn sich niemand freiwillig mit der Ausnahme befasst, kurz bevor der Microsoft WER-Dialog angezeigt wird.

Eigentlich etwas in diesem Rückruf zu tun ist voller Probleme. Das Programm ist ausnahmslos mit etwas Schädlichem wie einer AccessViolation-Ausnahme gestorben. Was oft durch Heap-Korruption ausgelöst wird. Der Versuch, etwas wie das Anzeigen eines Meldungsfelds zu tun, um den Benutzer wissen zu lassen, ist mühsam, wenn der Heap Toast ist. Immer wieder lauert der Deadlock um die Ecke, bereit, das Programm ohne jegliche Diagnose zu sperren.

Die einzige sichere Sache ist, einen Hilfsprozess zu haben, der Ihren Hauptprozess schützt. Aktivieren Sie es, indem Sie in Ihrem Callback ein benanntes Ereignis signalisieren. Geben Sie ihm die Ausnahmeinfo, die er benötigt, mit einer Memory-Mapped-Datei. Der Helfer kann so ziemlich alles machen, was er will, wenn er das Ereignis signalisiert sieht. Einschließlich das Zeigen einer Nachricht, das Nehmen eines Minidumps. Und den Hauptprozess beenden.

Genau so funktioniert der Microsoft WerFault-Helfer.

+0

UEFs sind im Allgemeinen problematisch und unzuverlässig. Es gibt einige seltene Umstände, unter denen sie vom System nicht zurückgerufen werden, selbst wenn sie es sein sollten. Sie sind auch global und könnten von frechen Shell-Erweiterungen, Bibliotheken von Drittanbietern usw. überschrieben werden. Aufruf von 'WerAddExcludedApplication' (vorgeschlagen von Benutzer" mdb ") oder Aufruf von' SetErrorMode' mit 'SEM_NOGPFAULTERRORBOX' (vorgeschlagen von Benutzer" Jan Goyvaerts ") sind beide robuster. – Donpedro

5

Hans Passants Antwort über SetUnhandledExceptionFilter ist auf dem richtigen Weg. Er macht auch einige gute Punkte, wenn es darum geht, im Callback nicht zu viel zu tun, da sich verschiedene Teile des Prozesses in einem instabilen Zustand befinden könnten.

Von der Art und Weise, wie das Problem beschrieben wird, klingt es jedoch nicht so, als ob Sie etwas tun möchten, außer dass das System den normalen Crash-Dialog nicht aufruft. In diesem Fall ist es einfach und sollte sicher sein, unabhängig davon, welche Teile des Prozesses vom Absturz betroffen sein könnten.

eine Funktion so etwas wie dieses Fabrikat:

LONG WINAPI UnhandledExceptionCallback(PEXCEPTION_POINTERS pExceptPtrs) 
{ 
    if (IsDebuggerPresent()) 
     // Allow normal crash handling, which means the debugger will take over. 
     return EXCEPTION_CONTINUE_SEARCH; 
    else 
     // Say we've handled it, so that the standard crash dialog is inhibited. 
     return EXCEPTION_EXECUTE_HANDLER; 
} 

Und irgendwo in Ihrem Programm (wahrscheinlich so früh wie möglich) den Rückruf:

SetUnhandledExceptionFilter(UnhandledExceptionCallback); 

das tun sollten, was Sie wollen - erlauben eine beliebige Abstürze dieses bestimmten Programms, um still zu sterben.

Es gibt jedoch noch etwas zu beachten: Jedes Mal, wenn Sie Komponenten von Drittanbietern (DLLs, OCXs, etc.) einbringen, besteht die Gefahr, dass einer von ihnen auch SetUnhandledExceptionFilter aufruft und somit Ihren Callback durch ihren eigenen ersetzt . Ich bin einmal auf ein ActiveX-Steuerelement gestoßen, das bei der Instanziierung einen eigenen Rückruf festlegen würde. Und noch schlimmer, es ist nicht gelungen, den ursprünglichen Rückruf wiederherzustellen, als er zerstört wurde. Das schien ein Fehler in ihrem Code zu sein, aber ich musste trotzdem zusätzliche Schritte unternehmen, um sicherzustellen, dass mein gewünschter Callback zumindest wiederhergestellt wurde, nachdem er heruntergefahren wurde. Wenn Sie also feststellen, dass dies manchmal nicht für Sie funktioniert, selbst wenn Sie wissen, dass Sie den Rückruf richtig eingestellt haben, können Sie auf etwas Ähnliches stoßen.

+0

Das geht nicht, nichts wurde behandelt. Es wird nur den fehlerhaften Befehl erneut starten, Absturz auf die gleiche Weise. Endlosschleife. –

+0

Zugegeben, ich schrieb dies basierend auf einer Kombination aus Speicher und einem Auszug aus altem Code, der das nicht mehr testen konnte. Aber ich habe es einfach in ein schnelles Testprogramm gesteckt, das mich zum Absturz brachte, indem ich versuchte, einen NULL-Zeiger zu verwenden, und es scheint so zu funktionieren, wie ich es wollte. Ich sehe es still enden, nicht Schleife. Wäre es nicht EXCEPTION_CONTINUE_EXECUTION, dass es in der fehlerhaften Anweisung fortgesetzt wird? – TheUndeadFish

+1

Wenn ich mich nicht irre, hat es keinen Sinn, in Ihrem UEF-Callback nach einem Debugger zu suchen ('IsDebuggerPresent'), da diese überhaupt nicht zurückgerufen werden, wenn ein Debugger vorhanden ist. – Donpedro

2

Ich fand mich in genau dieser Situation während der Entwicklung einer Delphi-Anwendung. Ich habe festgestellt, dass ich zwei Dinge benötigt habe, um das Dialogfeld "App funktioniert nicht mehr" zuverlässig zu unterdrücken.

Der Aufruf SetErrorMode(SEM_NOGPFAULTERRORBOX); unterdrückt das Dialogfeld "App hat aufgehört zu arbeiten". Dann zeigt der Ausnahme-Handler von Delphi stattdessen ein Meldungsfeld mit einer Laufzeitfehlermeldung an.

Um den Exception-Handler von Delphi zu unterdrücken, rufe ich SetUnhandledExceptionFilter mit einem benutzerdefinierten Handler auf, der den Prozess durch Aufruf von Halt beendet.

So das Skelett für eine Delphi-Client-Anwendung, den Code anfällig für Abstürze läuft wird:

function HaltOnException(const ExceptionInfo: TExceptionPointers): Longint; stdcall; 
begin 
    Halt; 
    Result := 1; // Suppress compiler warning 
end; 

begin 
    SetErrorMode(SEM_NOGPFAULTERRORBOX); 
    SetUnhandledExceptionFilter(@HaltOnException); 
    try 
    DoSomethingThatMightCrash; 
    except 
    on E: Exception do 
     TellServerWeFailed(E.Message); 
    end; 
end. 
+0

Für Visual C++ in vielen Fällen nur mit SetErrorMode (SEM_NOGPFAULTERRORBOX); reicht aus. –

Verwandte Themen