应用程序是否有办法从非托管访问冲突异常中恢复?

use*_*353 2 .net unmanaged exception

我有一个C#应用程序使用一些非托管的GDI +功能,我得到一个(非托管?)异常:

Log Name: Application
Source: .NET Runtime
Date: 7/1/2013 9:14:58 AM
Event ID: 1026
Task Category: None
Level: Error
Keywords: Classic
User: N/A
Computer: sth
Description:
Application: sth
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪是:

at System.Drawing.SafeNativeMethods+Gdip.IntGdipDisposeImage(System.Runtime.InteropServices.HandleRef)
at System.Drawing.SafeNativeMethods+Gdip.IntGdipDisposeImage(System.Runtime.InteropServices.HandleRef)
at System.Drawing.Image.Dispose(Boolean)
at System.Drawing.Image.Dispose()
at “..()
at Aspose.Cells.Charts.Chart.ToImage(System.IO.Stream, Aspose.Cells.Rendering.ImageOrPrintOptions)
Run Code Online (Sandbox Code Playgroud)

我可以防止它完全崩溃吗?我尝试过使用不带参数的catch语句,但是告诉我这还不够.我用这些有缺陷的代码创建了我自己的C++ DLL,似乎没有任何工作,除非DLL抛出:

__declspec(dllexport) void __cdecl Function1(void) // This doesn't get caught.
{
    char *chrs = new char[1000];
    delete []chrs;
    delete []chrs;
}

__declspec(dllexport) void __cdecl Function3(void) // This doesn't get caught.
{
    try
    {
        MessageBox(NULL, L"AAA", L"Caption", MB_OK);
        char *chrs = NULL;
        chrs[0] = 'a';
    }
    catch(...)
    {
        MessageBox(NULL, L"BBB", L"Caption", MB_OK); // I get no messagebox here... (probably it doesn't get caught)
    }
}

__declspec(dllexport) void __cdecl Function2(void) // This gets caught as a .NET Exception.
{
    throw "Oh My!";
}
Run Code Online (Sandbox Code Playgroud)

那么,我可以做某事来阻止我的EXE崩溃吗?

编辑

此外,是否System.AccessViolationException意味着这是一个托管例外?如果,是的,我想知道为什么我没有抓住它......我的代码包含在try {} catch(){}中...

EDIT2

我的猜测是GDI +会破坏堆,而CLR会在稍后检测到它并抛出异常.但它不能被捕获,因为它不是从try块中抛出的.我能在这种情况下做某事吗?

Han*_*ant 6

有些例外是令人讨厌的,它们表明你的计划中有一个非常重大的不幸事件.有些是如此令人讨厌,以至于完全无法从这种情况中恢复过来.该网站的名称属于该类别.ExecutionEngineException也是如此.这些是如此令人讨厌,以至于catch块仍能正常执行的几率为零.他们立即终止您的计划.

System.AccessViolationException只是一个非常讨厌的头发,让我们称之为超级讨厌.当处理器发现它不能再执行代码时,它会生成异常.当然致命的程序.有几个可能的原因,最典型的是无效的机器代码指令或访问不可读或不可写的存储器位置.堆损坏是内存访问问题的一个非常典型的原因.

捕获异常在技术上是可行的,因为异常处理会使处理器远离不再执行的代码,并迫使它继续在其他地方继续运行.因此CLR不会被迫终止该程序.然而,这是一个非常强烈的迹象,表明您的程序状态严重受损.这种腐败很少被孤立.

当你处理一个位图时,看到它的爆炸点大量指向这种腐败.很可能它是一个被损坏的非托管堆,由GDI +用来存储位图的像素数据.这种类型的损坏通常不是由GDI +本身引起的,它可能是在程序中运行的其他非托管代码,当它碰到指针时将垃圾喷射到堆中.

你可以旋转命运之轮并抓住异常.但是,当你的程序访问那些破碎的堆上的数据时,你的程序继续轰炸AV的可能性很高.轰炸OutOfMemoryException也很有可能.毕竟,你打算释放非托管内存,但这并没有发生.这种情况发生在以后,它可以造成更多的伤害,并提供更少的方法来诊断导致它的原因.就像终结者一样,它也会爆炸.这是致命的,当终结器抛出未处理的异常时,CLR终止程序.

抓住它真的只是一个绑带,你真的需要解决根本原因.然而,这很困难,代码中堆损坏使AV跳闸的位置永远不会接近导致损坏的代码.换句话说,怀疑GDI +是原因并不能帮助你找到原因.它实际上是不可能的原因,GDI +是一个经过严格测试的代码块,每天运行数十亿次.

如果您不怀疑自己进程中的非托管代码,则通过在另一台计算机上测试您的程序来隔离问题.可能就像在使用OpenFileDialog时加载到进程中的错误的shell扩展一样简单.如果您这样做,则通常需要为程序中使用的任何非托管代码编写单元测试.祝它好运.