从非托管代码进入CLR的线程中的未处理异常不会触发“正常”未处理异常CLR处理。
在下面的代码中使用
从C ++调用CSSimpleObject.GetstringLength()
如果是“1”
如果是“2”(预期行为)
要做出“正常”行为需要做些什么?
以下代码基于Visual Studio 2010“CppHostCLR”代码示例 来自“all interop and fusion samples”。
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创建的线程中的未处理异常应该或多或少“自然” - 请参阅“Exceptions in Managed Threads”
公共语言运行库允许线程中大多数未处理的异常自然地继续。在大多数情况下,这意味着未处理的异常导致应用程序终止。“
“Most”意味着在CLR创建的线程内部,线程中止和Application Domain卸载异常的处理方式不同。在非CLR线程中
“他们正常进行,导致申请终止。”
进一步的研究使我“Unhandled Exception Processing In The CLR”,在那里我发现了以下内容:
“如果未处理异常...在托管方法中,异常将退出CLR但继续向上传播堆栈作为本机SEH异常(托管异常表示为本机SEH异常)... OS未处理的异常过滤器(UEF)机制可能不总是导致触发CLR的未处理异常处理。 在正常情况下,这将按预期工作,并且将触发CLR的未处理异常处理。但是,在某些情况下,这可能不会发生。“
上面的代码有什么问题或者如何更改以便触发CLR的未处理异常处理?
我刚刚发现了一个旧的错误报告,“当从非托管调用托管代码并抛出异常时,未调用UnhandledExceptionEventHandler - http://tinyurl.com/44j6gvu”,Microsoft确认这是一个“错误”行为:
感谢您抽出宝贵时间报告此问题。 行为确实是由CLR执行引擎和CRT竞争UnhandledExceptionFilter 引起的错误。 CLR的体系结构已在支持此方案的4.0版本中进行了修订。
为什么要做到这一点很重要?
注意:通过SetActionOnFailure()
改变CLR行为会使情况变得更糟,因为它最终掩盖了原始异常(即,最终看到threadAborts而不是内存不足 - 没有线索原始错误来自哪里!)
答案 0 :(得分:2)
此更新意味着您可能在此处拥有解决方案。但是,它的解决方案并不适用于所有情况,因此这里有更多信息。
如果您更喜欢CLR Unhandled Exception行为,那么将其作为最外层程序并仅调用本机代码来执行特定功能。这将确保CLR控制未处理的异常过滤器。
如果你想保留你当前的结构和你所拥有的C ++代码很小,你可以完全停止使用CRT(这将拒绝你一堆有用的东西,包括静态构造函数和C ++异常处理)。这将确保CLR获得未处理的异常过滤器。
当然,你可以自己调用SetUnhandledExceptionFilter并获得你想要的行为。
但是,我认为在这种情况下最好的建议是在任何线程的调用堆栈上放置一个带有catch块的实际函数,在发生异常时你想做某事而不依赖于UEF机制 - 因为在组件系统的环境中,当多个用户竞争它时,它总是很脆弱。
马丁