在非CLR创建的线程中进行CLR托管异常处理

|| 问题: 从非托管代码进入CLR的线程中未处理的异常不会触发\“ normal \”未处理的异常CLR处理。 在下面的代码中,使用C从C ++调用
CSSimpleObject.GetstringLength()
\“ 1 \”在调用线程(非CLR创建的线程)中引发异常, \“ 2 \”在新的Thread()(CLR创建的线程)中引发异常。 如果\“ 1 \” 从不调用CurrentDomain_UnhandledException()。 应用程序域和进程将保持加载和运行状态,您只会得到失败。 万一\“ 2 \”(预期行为) 调用CurrentDomain_UnhandledException()。 该过程被杀死。 问题: 要获得“正常”行为必须做什么? 样例代码: 下面的代码基于Visual Studio 2010 \“ CppHostCLR \”代码示例 来自“所有互操作和融合样本”。 RuntimeHost(C ++):
PCWSTR pszStaticMethodName = L\"GetStringLength\";
PCWSTR pszStringArg = L\"1\";
//PCWSTR pszStringArg = L\"2\";

hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyPath,
    pszClassName, pszStaticMethodName, pszStringArg, &dwLengthRet);
if (FAILED(hr))
{
    wprintf(L\"Failed to call GetStringLength w/hr 0x%08lx\\n\", hr);
    goto Cleanup;
}
托管代码(C#):
public class CSSimpleObject
{
    public CSSimpleObject()
    {
    }
    //------8<----------
    public static int GetStringLength(string str)
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        switch (str)
        {
            case \"1\":
                throw new Exception(\"exception in non-CLR-created thread\");
            case \"2\":
                Thread thread = new Thread(new ThreadStart(WorkThreadFunction));
                thread.Start();
                break;
        }
        return str.Length;

    }
    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine(\"CurrentDomain_UnhandledException:\" + e.ToString());
        Console.ReadKey();
    }
    public static void WorkThreadFunction()
    {
        throw new Exception(\"\"exception in CLR-created thread\"\");
    }
到目前为止的研究: MSDN最初暗示,非CLR创建的线程中未处理的异常应该或多或少地“自然地”表现-请参见“托管线程中的异常”   公共语言运行时允许线程中大多数未处理的异常自然进行。在大多数情况下,这意味着未处理的异常会导致应用程序终止。\“ \“ Most \”表示在CLR创建的线程内部,线程异常中止和Application Domain卸载异常的处理方式不同。在非CLR线程中   \“它们正常进行,导致应用程序终止。” 进一步的研究使我找到了“ CLR中未处理的异常处理”,在其中我发现了以下内容:   \“如果未在托管方法中处理异常,则该异常将退出CLR,但会继续作为本机SEH异常向上传播到堆栈(托管异常表示为本机SEH异常)...   操作系统未处理异常过滤器(UEF)机制可能并不总是导致触发CLR的未处理异常处理。   在正常情况下,这将按预期工作,并且将触发CLR的未处理异常处理。但是,在某些情况下,这可能不会发生。” 上面的代码有什么问题,或者如何更改它以便触发CLR的未处理异常处理? 更新(2011-05-31): 我刚刚发现了一个旧的错误报告,“从非托管状态调用托管代码并引发异常时,未调用UnhandledExceptionEventHandler-http://tinyurl.com/44j6gvu”,Microsoft确认这是“越野车”行为:   感谢您抽出宝贵时间报告此问题。该行为确实是由CLR执行引擎和CRT竞争UnhandledExceptionFilter引起的错误。 CLR的体系结构已在支持此方案的4.0版本中进行了修订。 更新(2011-06-06): 为什么正确解决这个问题很重要? 如果您正在创建主机环境,则开发人员希望异常处理中的行为一致 除非有一种方法可以在本机线程中触发“常规CLR异常处理”,否则这意味着您始终必须将执行转移到托管线程(例如,进入线程池) 仍然有少量的代码将执行从本机线程转移到托管线程...必须捕获所有异常并以某种方式不同地处理这种情况 注意:从表面上看,通过ѭ3更改CLR行为会使情况变得更糟,因为它最终掩盖了原始异常(即,不是内存不足,您最终会看到threadAborts-不知道原始错误源于何处!)     
已邀请:
更新意味着您可能在这里有解决方案。但是,它的解决方案并非在所有情况下都有效,因此这里有一些更多信息。 如果您更喜欢CLR未处理的异常行为,则使该程序位于最外面,并仅调用本机代码来执行特定功能。这将确保CLR获得对未处理异常过滤器的控制。 如果您想保留当前的结构,而C ++代码很小,则可以完全停止使用CRT(这将使您一堆有用的东西,包括静态构造函数和C ++异常处理)。这将确保CLR获得未处理的异常过滤器。 而且,当然,您可以自己调用SetUnhandledExceptionFilter并获得所需的行为。 但是,我认为在这种情况下,最好的建议是将一个带有catch块的实际函数放在您想在发生异常时执行某些操作而不依赖于UEF机制的任何线程的调用堆栈上-因为在上下文中在组件系统中,它总是脆弱的,因为有多个用户竞争它。 马丁     

要回复问题请先登录注册