【发布时间】:2011-03-19 17:27:03
【问题描述】:
我可以做些什么来捕捉AccessViolationException?它是由我无法控制的非托管 DLL 抛出的。
【问题讨论】:
标签: .net exception-handling unmanaged
我可以做些什么来捕捉AccessViolationException?它是由我无法控制的非托管 DLL 抛出的。
【问题讨论】:
标签: .net exception-handling unmanaged
您可以使用 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" 这样做。
【讨论】:
legacyCorruptedStateExceptionsPolicy=true。查看我的更新。
正如其他人指出的那样,您不应该“处理”这种情况,但在开发过程中,为了排除故障,可以方便地捕捉到这种情况。
您可以使用System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions 属性标记您的托管方法:
[HandleProcessCorruptedStateExceptions]
public void MyMethod()
{
try
{
NaughtyCall();
}
catch (AccessViolationException e)
{
// You should really terminate your application here
}
}
【讨论】:
你不应该。访问冲突是一个严重的问题:它是对无效内存地址的写入(或读取)的意外尝试。正如 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。上面链接的文章中的更多详细信息。
【讨论】:
是的。
在您的 App.confg 中,将以下代码放入 <configuration> 标记中:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
现在您应该能够像其他任何情况一样捕获损坏的状态异常 (CSE)。
注意:如果您已经有一个运行时标签,那么只需将<legacyCorruptedStateExceptionsPolicy enabled="true"/> 添加到它
以上适用于.Net 4.5
【讨论】:
<legacyCorruptedStateExceptionsPolicy enabled="true"/> 添加到app.config”,但没有人说不应该在默认的<startup> 部分中。感谢<runtime> 部分的提示
首先,我完全同意 0xA3。但是如果没有出路,您可以将脏的非托管 dll 包装在自己的进程中并通过 IPC(TCP/IP、namedpipes 等)传输数据。捕获所有异常并通知主机进程。所以你的主机进程主要是从内存损坏中拯救出来的。
【讨论】: