如何处理AccessViolationException

时间:2010-08-12 15:33:01

标签: c# .net exception com modi

我在.net应用程序中使用COM对象(MODI)。我调用的方法抛出一个System.AccessViolationException,它被Visual Studio拦截。奇怪的是我在try catch中包含了我的调用,它包含AccessViolationException,COMException和其他所有东西的处理程序,但是当Visual Studio(2010)拦截AccessViolationException时,调试器会中断方法调用(doc.OCR),如果我单步执行,它将继续到下一行,而不是进入catch块。另外,如果我在visual studio外部运行,我的应用程序崩溃了。如何处理COM对象中抛出的异常?

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();

}

5 个答案:

答案 0 :(得分:271)

在.NET 4.0中,运行时将作为Windows结构化错误处理(SEH)错误引发的某些异常处理为损坏状态的指示符。您的标准托管代码不允许捕获这些损坏的状态异常(CSE)。我不会深入了解为什么或如何在这里。阅读本文关于.NET 4.0 Framework中的CSE:

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

但是有希望。有几种方法可以解决这个问题:

  1. 重新编译为.NET 3.5程序集并在.NET 4.0中运行。

  2. 在配置/运行时元素下的应用程序配置文件中添加一行: <legacyCorruptedStateExceptionsPolicy enabled="true|false"/>

  3. 使用HandleProcessCorruptedStateExceptions属性装饰要捕获这些异常的方法。有关详细信息,请参阅http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035


  4. 修改

    之前,我引用了forum post了解更多详情。但是,由于Microsoft Connect已经停用,以下是您感兴趣的其他详细信息:

    来自Microsoft CLR团队的开发人员Gaurav Khanna

      

    由于CLR 4.0的一个名为Corrupted State Exceptions的功能,此行为是设计使然。简单地说,托管代码不应该尝试捕获指示损坏的进程状态的异常,AV就是其中之一。

    然后,他继续参考HandleProcessCorruptedStateExceptionsAttribute和上述文章中的文档。可以说,如果您正在考虑捕获这些类型的异常,那绝对值得一读。

答案 1 :(得分:13)

在配置文件中添加以下内容,它将在try catch块中捕获。 谨慎......尽量避免这种情况,因为这意味着发生了某种违规行为。

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

答案 2 :(得分:6)

从上面的答案编译,为我工作,做了以下步骤来抓住它。

步骤#1 - 将以下代码段添加到配置文件

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

第2步

添加 -

[HandleProcessCorruptedStateExceptions]

[SecurityCritical]

在你正在搭便车的功能顶部捕捉异常

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

答案 3 :(得分:1)

您可以尝试使用AppDomain.UnhandledException,看看是否可以抓住它。

**编辑*

以下是一些可能有用的more information(这是一个长读)。

答案 4 :(得分:0)

Microsoft “损坏的进程状态异常是表示进程状态已损坏的异常。我们不建议在此执行您的应用程序状态.....如果您绝对确定要维持对这些异常的处理,则必须应用HandleProcessCorruptedStateExceptionsAttribute属性“

Microsoft “使用应用程序域隔离可能导致进程中断的任务。”

下面的程序将保护您的主应用程序/线程免受不可恢复的故障的影响,而没有使用HandleProcessCorruptedStateExceptions<legacyCorruptedStateExceptionsPolicy>的风险

public class BoundaryLessExecHelper : MarshalByRefObject
{
    public void DoSomething(MethodParams parms, Action action)
    {
        if (action != null)
            action();
        parms.BeenThere = true; // example of return value
    }
}

public struct MethodParams
{
    public bool BeenThere { get; set; }
}

class Program
{
    static void InvokeCse()
    {
        IntPtr ptr = new IntPtr(123);
        System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
    }

    private static void ExecInThisDomain()
    {
        try
        {
            var o = new BoundaryLessExecHelper();
            var p = new MethodParams() { BeenThere = false };
            Console.WriteLine("Before call");

            o.DoSomething(p, CausesAccessViolation);
            Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
        }
        catch (Exception exc)
        {
            Console.WriteLine($"CSE: {exc.ToString()}");
        }
        Console.ReadLine();
    }


    private static void ExecInAnotherDomain()
    {
        AppDomain dom = null;

        try
        {
            dom = AppDomain.CreateDomain("newDomain");
            var p = new MethodParams() { BeenThere = false };
            var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);         
            Console.WriteLine("Before call");

            o.DoSomething(p, CausesAccessViolation);
            Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
        }
        catch (Exception exc)
        {
            Console.WriteLine($"CSE: {exc.ToString()}");
        }
        finally
        {
            AppDomain.Unload(dom);
        }

        Console.ReadLine();
    }


    static void Main(string[] args)
    {
        ExecInAnotherDomain(); // this will not break app
        ExecInThisDomain();  // this will
    }
}