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();
}
#1 楼
在.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中运行。
在应用程序的配置文件下添加一行配置/运行时元素:
<legacyCorruptedStateExceptionsPolicy enabled="true|false"/>
使用
HandleProcessCorruptedStateExceptions
属性装饰您要捕获这些异常的方法。有关详细信息,请参见http://msdn.microsoft.com/zh-cn/magazine/dd419661.aspx#id0070035。编辑
以前,我引用过有关更多详细信息的论坛帖子。但是,由于Microsoft Connect已停用,因此,如果您有兴趣,这里还有其他详细信息:
来自Microsoft CLR团队的开发人员Gaurav Khanna
此行为是由于CLR 4.0的一项功能而设计的,该功能称为“损坏的状态异常”。简而言之,托管代码不应尝试捕获表示损坏的进程状态的异常,而AV就是其中之一。
然后他继续引用HandleProcessCorruptedStateExceptionsAttribute及其以上的文档。文章。可以说,如果您考虑捕获这些类型的异常,绝对值得一读。
评论
.Net 4.5中的HandleProcessCorruptedStateExceptions对我有用。
– Deerchao
13年5月26日在8:56
谢谢villecoder,您是一颗宝石!我已经解决这个问题好几个星期了,试图解决根本问题,最后辞职去治疗症状。您的解决方案是完美的。
– gadildafissh
13年7月30日在18:45
!请注意:强烈建议在AccessViolationException之后将其终止,该过程是Corrupted State Exception(CSE)。否则会导致更严重的错误。
–克里斯·W
2014年12月8日14:56
谢谢,这确实有帮助,尽管起初我觉得我需要完成所有三个步骤才能捕获这些异常,而实际上这是执行这些方法的“逻辑或”。 :)
–楼
16-10-10在9:58
@deerchao我希望您已阅读答案中提供的第一个链接。处理CSE异常不是一个好主意。
–像素
17年2月20日在22:33
#2 楼
在配置文件中添加以下内容,它将被捕获在try catch块中。小心提示...请避免这种情况,因为这意味着某种违规行为正在发生。
<configuration>
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
</configuration>
评论
对于使用c ++ / cli作为dll的用户,应将代码添加到顶部的.exe项目中。
–费利克斯
17年6月20日在2:34
#3 楼
从上面的答案中编译出来,为我工作,做了以下步骤来对其进行捕获。步骤1-将以下代码段添加到配置文件中
<configuration>
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
</configuration>
步骤#2
添加-
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
在要绑定的函数顶部捕获异常
来源:http://www.gisremotesensing.com/2017/03/catch-exception-attempted-to-read-or.html
评论
根据msdn.microsoft.com/zh-cn/library/…,SecurityCriticalAttribute等效于对完全信任的链接需求。我认为所描述的问题并不需要完全信任。
–杰里米
17 Mar 23 '17 at 18:59
#4 楼
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
}
}
#5 楼
您可以尝试使用AppDomain.UnhandledException,看看是否可以捕获它。** EDIT *
这里有一些更多有用的信息(阅读了很长时间) )。
评论
由于.NET框架的变化,此答案不再完全准确。在4.0之前是正确的。 msVn.microsoft.com/zh-cn/library/…中的AccessViolationException和try / catch块的每个部分
–特福德
17年8月11日在17:52
评论
您是否尝试过(临时!)放入一个Exception处理程序以捕获所有异常并查看实际的异常是什么?@ChrisF-是的,看到最后一个捕获处理程序了吗?那应该捕获所有东西,包括Exception和Exception的任何子类。同样,Visual Studio报告该异常是System.AccessViolationException