本机线程崩溃的例外.Net应用程序无一例外

我发现了一个场景,我的.Net应用程序会意外崩溃而不会引发任何异常.我想,至少AppDomain.UnhandledException在这种情况下有效,为了使我至少能够记录错误并向用户提供一些信息.

在这种情况下,我有一个.Net程序集(让我们称之为A)与对本机DLL(我们称之为B)的互操作调用. B创建一个线程并抛出;没有人能够捕获异常,我希望它能够一直向上堆栈,回到我的托管应用程序,最后成为一个未处理的异常.

此时我希望操作系统将控制权交还给.Net,它会调用AppDomain.UnhandledException,然后我的应用程序就会结束.但是,呼叫永远不会发生.

下面我提供了足够的信息来重现这个问题.它可以被忽略.

Program.cs中

internal class Program
{
    public static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += _currentDomainUnhandledException;
        try
        {
            BugDllInterop.ErrorMethod(0);
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e.GetType().Name);
        }            

        Console.WriteLine("Clean exit.");
    }

    private static void _currentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("Exception trapped.");
    }
}

BugDllInterop.cs

public static class BugDllInterop
{
    private const string BUG_DLL = "InteropExceptions.BugDll.dll";

    [DllImport(BUG_DLL, CallingConvention = CallingConvention.Cdecl)]
    public extern static void ErrorMethod(int i);
}

BugDll.h

// INCLUSION GUARD
#pragma once

#define DllExport __declspec(dllexport) 

extern "C" 
{
    DllExport void ErrorMethod(int i);
}

BugDll.cpp

// HEADER /////////////////////////////////////////////////////////////////////
#include "BugDll.h"

// LIBRARIES //////////////////////////////////////////////////////////////////
#include <windows.h>
#include <fstream>
#include <iostream>
#include <time.h>

using namespace std;

// FUNCTIONS //////////////////////////////////////////////////////////////////

DWORD WINAPI threadMethod(LPVOID lpParameter)
{
    throw 0;

    return 0;
}

void ErrorMethod(int i)
{

    DWORD myThreadID;
    HANDLE myHandle = CreateThread(0, 0, threadMethod, 0, 0, &myThreadID);
    WaitForSingleObject(myHandle, 3000);
    CloseHandle(myHandle);

}

同样,我希望只是引发AppDomain.UnhandledException事件.当然,如果有人知道如何正确处理异常以保持应用程序活着,那就更好了.

最佳答案 您无法捕获和管理从另一个非托管线程抛出的异常.

当方法抛出异常时,CLR将仅在抛出异常的线程中搜索处理程序.它甚至可以理解,因为线程的调用堆栈以线程本身开头.

您有一个根异常处理程序,因为CLR将处理程序放在顶层(将调用您的过滤器),但对于非托管线程则不然,因此无法转发它们的异常.

这种情况的唯一解决方案是在它们发起的线程中捕获异常.如果您的线程函数可以抛出异常,那么在那里添加一个catch.无论如何不在管理方面.托管/非托管边界非常厚实.

您可能希望阅读有关异常处理的这篇好文章:http://www.microsoft.com/msj/0197/exception/exception.aspx

点赞