Umgang mit AccessViolationException

183

Ich verwende ein COM-Objekt (MODI) in meiner .net-Anwendung. Die von mir aufgerufene Methode löst eine System.AccessViolationException aus, die von Visual Studio abgefangen wird. Das Seltsame ist, dass ich meinen Aufruf in einen Try-Catch eingeschlossen habe, der Handler für AccessViolationException, COMException und alles andere enthält. Wenn Visual Studio (2010) die AccessViolationException abfängt, bricht der Debugger den Methodenaufruf (doc.OCR) ab. und wenn ich durchtrete, geht es weiter zur nächsten Zeile, anstatt den Fangblock zu betreten. Wenn ich dies außerhalb des Visual Studios ausführe, stürzt meine Anwendung ab. Wie kann ich mit dieser Ausnahme umgehen, die im COM-Objekt ausgelöst wird?

MODI.Document doc = new MODI.Document();
try
{
    doc.Create(sFileName);
    try
    {
        doc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, false, false);
        sText = doc.Images[0].Layout.Text;
    }
    catch (System.AccessViolationException ex)
    {
        //MODI seems to get access violations for some reason, but is still able to return the OCR text.
        sText = doc.Images[0].Layout.Text;
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
        //if no text exists, the engine throws an exception.
        sText = "";
    }
    catch
    {
        sText = "";
    }

    if (sText != null)
    {
        sText = sText.Trim();
    }
}
finally
{
    doc.Close(false);

    //Cleanup routine, this is how we are able to delete files used by MODI.
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
    doc = null;
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();

}
Jeremy
quelle
Haben Sie versucht, einen ExceptionHandler (vorübergehend!) Einzusetzen, um alle Ausnahmen abzufangen und festzustellen, was die Ausnahme tatsächlich ist?
ChrisF
3
@ChrisF - ja, sehen Sie den letzten Catch-Handler? Das sollte alles erfassen, einschließlich Ausnahme und jeder Unterklasse von Ausnahme. Außerdem berichtet Visual Studio, dass die Ausnahme System.AccessViolationException
Jeremy

Antworten:

298

In .NET 4.0 behandelt die Laufzeit bestimmte Ausnahmen, die als SEH-Fehler (Windows Structured Error Handling) ausgelöst werden, als Indikatoren für den beschädigten Status. Diese CSE (Corrupted State Exceptions) dürfen von Ihrem standardmäßigen verwalteten Code nicht abgefangen werden. Ich werde nicht auf das Warum oder Wie hier eingehen. Lesen Sie diesen Artikel über CSEs in .NET 4.0 Framework:

http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035

Aber es gibt Hoffnung. Es gibt einige Möglichkeiten, dies zu umgehen:

  1. Kompilieren Sie als .NET 3.5-Assembly neu und führen Sie sie in .NET 4.0 aus.

  2. Fügen Sie der Konfigurationsdatei Ihrer Anwendung unter dem Konfigurations- / Laufzeitelement eine Zeile hinzu: <legacyCorruptedStateExceptionsPolicy enabled="true|false"/>

  3. Dekorieren Sie die Methoden, mit denen Sie diese Ausnahmen abfangen möchten, mit dem HandleProcessCorruptedStateExceptionsAttribut. Weitere Informationen finden Sie unter http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035 .


BEARBEITEN

Zuvor habe ich für weitere Details auf einen Forumsbeitrag verwiesen . Da Microsoft Connect jedoch eingestellt wurde, finden Sie hier weitere Details, falls Sie interessiert sind:

Von Gaurav Khanna, einem Entwickler des Microsoft CLR-Teams

Dieses Verhalten ist beabsichtigt auf eine Funktion von CLR 4.0 zurückzuführen, die als Ausnahmen für beschädigte Zustände bezeichnet wird. Einfach ausgedrückt, verwalteter Code sollte nicht versuchen, Ausnahmen abzufangen, die auf einen beschädigten Prozessstatus hinweisen, und AV ist eine davon.

Anschließend verweist er auf die Dokumentation zum HandleProcessCorruptedStateExceptionsAttribute und den obigen Artikel. Es genügt zu sagen, dass es definitiv eine Lektüre wert ist, wenn Sie erwägen, diese Art von Ausnahmen zu erwischen.

villecoder
quelle
10
HandleProcessCorruptedStateExceptionsfunktioniert für mich in .Net 4.5.
Deerchao
2
Danke villecoder, du bist ein Juwel! Ich beschäftige mich seit Wochen mit diesem Problem, versuche das Grundproblem zu lösen und habe mich schließlich damit abgefunden, das Symptom zu behandeln. Ihre Lösung ist perfekt.
Gadildafissh
19
! Beachten Sie: Es wird dringend empfohlen, den Prozess nach der AccessViolationException zu beenden, bei der es sich um eine CSE (Corrupted State Exception) handelt. Andernfalls kann es zu kritischeren Fehlern kommen.
Zbigniew Wiadro
6
Danke, das ist wirklich hilfreich, obwohl ich zuerst den Eindruck hatte, dass ich alle drei Schritte ausführen muss, um diese Ausnahmen abfangen zu können, während es eigentlich eine "logische OR" Vorgehensweise ist. :)
Lou
@deerchao Ich hoffe, Sie haben den ersten Link als Antwort gelesen. Der Umgang mit CSE-Ausnahmen ist eine schlechte Idee.
Pixel
17

Fügen Sie der Konfigurationsdatei Folgendes hinzu, und es wird im try catch-Block abgefangen. Ein Wort der Vorsicht ... versuchen Sie, diese Situation zu vermeiden, da dies bedeutet, dass eine Art Verstoß vorliegt.

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>
Partha
quelle
2
Für diejenigen, die c ++ / cli als DLL verwenden, sollte der Code zum obersten EXE-Projekt hinzugefügt werden.
Felix
9

Aus den obigen Antworten zusammengestellt, für mich gearbeitet, folgende Schritte unternommen, um sie zu fangen.

Schritt 1 - Fügen Sie der Konfigurationsdatei das folgende Snippet hinzu

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>

Schritt 2

Hinzufügen -

[HandleProcessCorruptedStateExceptions]

[SecurityCritical]

Oben auf der Funktion binden Sie die Ausnahme

Quelle: http://www.gisremotesensing.com/2017/03/catch-exception-attempted-to-read-or.html

Teufel in dir
quelle
Laut msdn.microsoft.com/en-us/library/… entspricht das SecurityCriticalAttribute einer Linkanforderung für volles Vertrauen. Ich denke nicht, dass das beschriebene Problem die Forderung nach vollem Vertrauen erfordert.
Jeremy
0

Sie können versuchen, AppDomain.UnhandledException zu verwenden, und prüfen, ob Sie es damit abfangen können.

**BEARBEITEN*

Hier sind einige weitere Informationen , die nützlich sein könnten (es ist eine lange Lektüre).

Tony Abrams
quelle
2
Diese Antwort ist aufgrund von Änderungen im .NET Framework nicht mehr vollständig korrekt. Vor 4.0 ist es richtig. Pro Abschnitt von AccessViolationException und Try / Catch-Blöcke in msdn.microsoft.com/en-us/library/…
Tedford