我能做些什么来抓住AccessViolationException
吗?它是由我无法控制的非托管DLL引发的。
答案 0 :(得分:29)
你不应该。访问冲突是一个严重的问题:它是一种意外尝试写入(或读取)无效的内存地址。正如John已经阐明的那样,在提出访问冲突之前,非托管DLL可能已经损坏了进程内存。这可能会对当前流程的任何部分产生不可预测的影响。
最安全的做法是通知用户,然后立即退出。
更多详细信息:访问冲突是操作系统异常(所谓的SEH或结构化异常处理异常)。这是一种与System.Exception
的托管CLR异常不同的异常。您很少会在纯托管代码中看到SEH异常,但如果出现这种情况,例如在非托管代码中,CLR会将其提供给托管代码,您也可以将其捕获到 1 。
但是,捕获SEH例外通常不是一个好主意。有关详细信息,请参阅MSDN杂志中的Handling Corrupted State Exceptions一文,其中包含以下文字:
CLR始终使用与程序本身引发的异常相同的机制向托管代码提供SEH异常。只要代码不尝试处理无法合理处理的异常条件,这就不是问题。在访问冲突后,大多数程序无法安全地继续执行。不幸的是,CLR的异常处理模型总是鼓励用户通过允许程序捕获System.Exception层次结构顶部的任何异常来捕获这些严重错误。但这很难做到。
1 直到.NET 3.5才这样。在.NET 4中,行为已被更改。如果您仍希望能够捕获此类异常,则必须将legacyCorruptedStateExceptionsPolicy=true
添加到app.config。以上链接的更多细节。
答案 1 :(得分:8)
是。
在App.confg中,在<configuration>
标记中输入以下代码:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
现在你应该能够像其他任何一样捕获损坏的状态异常(CSE)。
注意:如果您已有运行时标记,则只需向其添加<legacyCorruptedStateExceptionsPolicy enabled="true"/>
以上适用于.Net 4.5
答案 2 :(得分:6)
正如其他人指出的那样,你不应该“处理”这种情况,但在开发过程中,为了排除故障,抓住它是很方便的。
您可以使用System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions
属性标记您的托管方法:
[HandleProcessCorruptedStateExceptions]
public void MyMethod()
{
try
{
NaughtyCall();
}
catch (AccessViolationException e)
{
// You should really terminate your application here
}
}
答案 3 :(得分:1)
首先,我完全熟悉0xA3。但是如果没有出路,你可以将脏的非托管dll包装在自己的进程中并通过IPC(TCP / IP,namedpipes等)传输数据。捕获所有异常并通知主机进程。因此,您的主机进程主要是通过内存损坏来节省的。
答案 4 :(得分:0)
您可以使用try-catch块将调用包装到非托管DLL。 AccessViolationExceptions可以正常捕获。执行以下代码会显示两条消息:
try
{
throw new AccessViolationException();
}
catch (Exception e)
{
MessageBox.Show(e.Message + e.StackTrace, e.Message, MessageBoxButtons.OK, MessageBoxIcons.Error);
}
MessageBox.Show("Still running..");
编辑: .NET 4引入了change in behavior,除非您专门"ask"运行时才能捕获已损坏的状态异常。