如何处理AccessViolationException

问题描述 投票:0回答:6

我在 .net 应用程序中使用 COM 对象 (MODI)。我调用的方法抛出一个

System.AccessViolationException
,它被 Visual Studio 拦截。奇怪的是,我将调用包装在 try catch 中,其中包含
AccessViolationException
COMException
和其他所有内容的处理程序,但是当 Visual Studio (2010) 拦截
AccessViolationException
时,调试器会在方法调用上中断(doc.OCR),如果我单步执行,它会继续到下一行,而不是进入 catch 块。此外,如果我在视觉工作室之外运行它,我的应用程序就会崩溃。如何处理 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();

}
c# .net exception com process-state-exception
6个回答
328
投票

编辑 (3/17/2021)

免责声明:此答案写于 2011 年,引用了原始 .NET Framework 4.0 实现,而不是 .NET 的开源实现。


在 .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


编辑

之前,我参考了论坛帖子以了解更多详细信息。但由于 Microsoft Connect 已停用,如果您感兴趣,以下是其他详细信息:

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

此行为是由于 CLR 4.0 的一项称为“损坏状态异常”的功能而设计的。简而言之,托管代码不应尝试捕获指示损坏的进程状态的异常,AV 就是其中之一。

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


22
投票

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

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

12
投票

根据上面的答案编译,为我工作,按照以下步骤捕获它。

步骤 #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
投票

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
    }
}

0
投票

** 这就是我处理 AccessViolationException 的方式:**

  [HandleProcessCorruptedStateExceptions]
  [SecurityCritical]
   private static ImageSource ImageSourceFromBitmap(System.Drawing.Bitmap bmp)
   {
        if (handle != IntPtr.Zero)
        {
            GC.SuppressFinalize(handle);
        }

        try
        {
            handle = bmp.GetHbitmap();
            BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            bitmapSource.Freeze();
            return bitmapSource;
        }
        catch (System.AccessViolationException exception)
        {
            Console.WriteLine($"{exception}Fail: CreateBitmapSourceFromHBitmap");
            throw new Exception();
        }
        finally
        {
            GC.SuppressFinalize(handle);
            DeleteObject(handle);
            
        }

    }

-1
投票

您可以尝试使用 AppDomain.UnhandledException 看看是否可以捕获它。

**编辑*

这里有一些可能有用的更多信息(读起来很长)。

© www.soinside.com 2019 - 2024. All rights reserved.