哪个.config元素会影响将UnhandledExceptionMode设置为UnhandledExceptionMode.Automatic时的异常处理?

9

我有一个Windows Forms应用程序,在程序启动时有以下代码:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.Automatic);

UnhandledExceptionMode.Automatic的MSDN文档中,它指出:

Automatic - 将所有异常路由到ThreadException处理程序,除非应用程序的配置文件另有规定。

有人知道配置文件中影响此设置的确切元素/属性是哪个吗?
2个回答

5

您可以像这样向配置文件添加JitDebugging部分:

<configuration>
  <system.windows.forms jitDebugging="true"/>
</configuration>

这相当于将UnhandledExceptionMode设置为UnhandledExceptionMode.ThrowException(顺便说一下,如果您在调试器附加的情况下运行应用程序,则此选项会自动启用)。

请注意,除非您另有指定,否则.Net默认使用UnhandledExceptionMode.Automatic;据我所知,显式将未处理异常模式设置为自动模式的唯一原因是想撤消先前更改为其他选项的调用。请注意,如果您将其设置为其他值而不是自动模式,则不会读取配置文件设置。

请注意,如果将ThreadException附加到当前AppDomain,则结果将自动与将UnhandledExceptionMode设置为UnhandledExceptionMode.CatchException相同。


因此,添加启用JitDebugging的配置(默认为false,对吧?)将切换模式以(有效地)ThrowException,以便将异常留给消息循环未处理,从而使其成为UnhandledException,如果用户选择从弹出窗口,则可以在该点激活应用程序的调试。 我理解得对吗?我认为这最终解释了文档中那个神秘的行,并回答了马丁最初的问题。+1,因为那个问题也困扰着我。 - Rob Parker
2
我终于有时间深入研究这个问题了,虽然这是具有影响的设置,但它是否具有影响还有一些复杂性。还有依赖于DebuggableAttribute上的IsJITDebugLaunchSetting标志以及以下两个注册表键的值:HKLM\Software\Microsoft.NETFramework -DbgJITDebugLaunchSetting和DbgManagedDebugger。 - Martin Brown

2
我也曾想过这个问题,但我从未能找到任何关于可设置的特定内置配置选项的信息(可能有一个,但我从未找到提到它是什么的)。我们还发现,默认行为(如果你不做任何操作)等同于ThrowException模式,这与MSDN在引用中所暗示的相反。此外,我认为将其设置为Automatic等同于根本不去碰它;它已经在启动时处于Automatic状态。
然而,我发现SetUnhandledExceptionMode有两个重载。正常的重载基于每个线程(通常你只有一个UI线程),但第二个重载还带有一个布尔值,该值确定设置是否仅应用于当前线程(true)或所有UI线程(false)。传递false就像为未来的UI线程设置默认设置一样,如果它们在启动时保持在Automatic模式下(我的意思是消息循环,即调用Application.Run),并且你可以将自己的配置选项连接到这个调用中以设置全局默认值。我不得不想知道他们所说的含糊的“config”参考是否就是这个。
警告是,调用SetUnhandledExceptionMode必须在同一上下文中创建任何窗口句柄之前完成。 因此,在任何线程上创建任何窗口句柄之前,必须使用false进行调用。此外,据称Visual Studio调试器会在代码启动之前存在一个窗口句柄,因此当进行调试时,这个调用永远不会成功(使用false)。但是,该窗口句柄不在您的线程上,因此在调试场景中可以安全地进行正常调用(或使用true)。我不确定在WinForms应用程序位于已创建的子域中而不是作为顶部/初始域的其他情况下,它会如何表现,是否子域继承了任何句柄创建标志或者能够重新开始。也许这就是Visual Studio案例的实际问题。
在创建任何窗口句柄之前,仍需在该线程上进行正常调用(或使用真实值)。我相信如果您在同一线程上重新进入Application.Run(与已创建的句柄标志一样),则此设置将持续存在于应用程序上下文退出后。但请注意,对Application.ThreadException的订阅是基于每个线程,每个上下文的基础,并且将在Application.Run退出时丢失。它还只能有一个订阅者(覆盖任何先前的订阅者),并且不能在消息循环运行时更改。因此,如果您再次调用Application.Run,则必须在调用Application.Run之前重新订阅Application.ThreadException,否则它们将被捕获并发送到默认的WinForms处理程序(我不是指UnhandledException),因为“异常模式”设置会持续存在。通常,您不会在同一线程上不断进入和退出消息循环,因此这不是问题,但我们在Gibraltar.Agent中遇到了这个问题,因为我们必须这样做。
"AppDomain.UnhandledException"是一个正常的事件,有多个订阅者,并不是线程特定的。只需订阅一次,就可以覆盖整个应用程序域(例如CurrentDomain)。"

感谢您添加链接,马丁。我花了一些时间才弄清楚您所更改的内容,因为编辑历史记录没有突出显示元数据的更改。现在我知道如何在这里创建链接了;我不会通过试错来弄清楚这个问题!不幸的是,我们仍在等待有关您特定问题的明确答案。 - Rob Parker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接