I am using a COM object (MODI) from within my .net application. The method I am calling throws a System.AccessViolationException, which is intercepted by Visual Studio. The odd thing is that I have wrapped my call in a try catch, which has handlers for AccessViolationException, COMException and everything else, but when Visual Studio (2010) intercepts the AccessViolationException, the debugger breaks on the method call (doc.OCR), and if I step through, it continues to the next line instead of entering the catch block. Additionally, if I run this outside of the visual studio my application crashes. How can I handle this exception that is thrown within the COM object?
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();
}
编辑(3/17/2021)
免责声明:这个答案写于2011年,引用了最初的。net Framework 4.0实现,而不是。net的开源实现。
在。net 4.0中,运行时处理某些异常,作为Windows结构化错误处理(SEH)错误作为损坏状态的指示器。标准托管代码不允许捕获这些损坏状态异常(CSE)。我就不讲原因了。阅读这篇关于。net 4.0框架中的CSE的文章:
http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035
但还是有希望的。有几种方法可以解决这个问题:
重新编译为. net 3.5程序集并在. net 4.0中运行。
在应用程序的配置文件的configuration/runtime元素下添加一行:
< legacyCorruptedStateExceptionsPolicy启用= "真|假" / >
使用HandleProcessCorruptedStateExceptions属性装饰您想要捕获这些异常的方法。详情见http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035。
EDIT
之前,我参考了一个论坛帖子来获得更多的细节。但由于Microsoft Connect已经退役,下面是额外的细节,以防你感兴趣:
来自微软CLR团队的开发人员Gaurav Khanna
这种行为是由于CLR 4.0的一个被称为损坏状态异常的特性而设计的。简单地说,托管代码不应该试图捕获指示已损坏进程状态的异常,AV就是其中之一。
然后,他继续引用关于HandleProcessCorruptedStateExceptionsAttribute的文档和上面的文章。可以这么说,如果您正在考虑捕获这些类型的异常,它绝对值得一读。
Microsoft:“损坏的进程状态异常是指示进程状态已损坏的异常。我们不建议在此状态下执行您的应用程序.....如果您绝对确定要维护对这些异常的处理,则必须应用HandleProcessCorruptedStateExceptionsAttribute属性。
微软:“使用应用程序域来隔离可能导致进程中断的任务。”
下面的程序将保护您的主应用程序/线程免受不可恢复的失败,而没有使用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
}
}