AppDomain.UnhandledException

时间:2016-10-06 15:45:56

标签: .net multithreading vb6 unhandled-exception

我们有一个.NET 3.5程序集(dll)由VB6"代理"执行。 (exe)通过COM接口。 VB6代码确实调用:

' Ensure that no system dialog comes up when we GPF.
PreviousErrorMode = SetErrorMode(SEM_NOGPFAULTERRORBOX)
SetErrorMode PreviousErrorMode Or SEM_NOGPFAULTERRORBOX

' Assign our Exception Handler for this process.
PreviousExceptionFilter = SetUnhandledExceptionFilter(AddressOf UnhandledExceptionFilter)

VB6 UnhandledExceptionFilter将异常转换为VB6引发的错误。 (但这里也没有被调用过,而且这些VB6代码多年来都没有被改变 - 甚至没有被重新编译过。)

在VB6代码创建的第一个.NET对象的构造函数中,我向AppDomain.CurrentDomain.UnhandledException添加了一个处理程序(并且,为了调试此问题,我为{{1}添加了一个但它没有帮助,不是说我们还有.NET显示的任何UI。)

在VS2008中开发此代码时,我确定Windows.Forms.Application.ThreadException事件已经抓住了,但我还不确定我是否已在VS2015中看到它。

代码运行多个线程,其中一些执行主要目的,包括插入和更新SQL Server数据,以及通过TCP协议进行通信,TCP协议由其他线程处理,包括UnhandledException

执行主要目的的人是:

BackgroundWorker

它太专有和复杂,无法向您显示更多代码,但我调整了代码,同时调试此问题只是taskThread = New Thread(AddressOf EnsureTaskCompletes) taskThread.SetApartmentState(Threading.ApartmentState.STA) taskThread.Start() 而不是最终具有相同效果的复杂代码。 (*)

这"简单" Throw New Exception没有处理异常,并且只是默默地终止了程序,除了我打开了非托管调试。

当.NET Framework仅为""时,UnhandledExceptionHandler的行为是否有文档记录的更改?加载为dll?

(由于COM重新注册,我不想在VS2008中构建以前的版本,但要确认行为更改。我确认由VS2015编译的.NET 3.5 Exe 创建AppDomain.CurrentDomain.UnhandledException,抛出未处理的异常 处理Thread事件中的异常。)< / p>

对我来说,解决方法是将UnhandledException添加到Catch中已经尝试至少记录线程在任务完成之前终止的Try Finally中,并调用EnusreTaskCompletes我自己。

(*实际问题是数据库中缺少的表格,只有在您用完信用卡时才会使用 - 我没有添加该代码或表格。 UnhandledExceptionHandler未捕获的异常,使其难以调试 - SQL Server Profiler终于找到了问题。)

2 个答案:

答案 0 :(得分:5)

这是一个不可思议的广泛话题,速度极快。不,当您从VB6调用代码时,您永远不会观察到UnhandledException事件。跨越互操作边界传递异常严格来说是 verboten

CLR遵守,它使用CCW中的catch-em-all异常处理程序来捕获异常。并将其转换为符合COM的HRESULT错误代码。每个.NET异常都有一个不同的Exception.HResult属性值。

VB6运行时又将它们转换为VB6错误。您需要使用On Error语句来捕获它们。 CLR实现IErrorInfo以提供一些信息,VB6 Err.Number属性具有Exception.HResult值,Err.Description为您提供Exception.Message属性值。但是,如果您需要InnerException属性来诊断事故,那么将获得Holy Stacktrace并且会非常不方便。请考虑使用AppDomain.FirstChanceException事件来记录详细信息。

调试这样的异常很容易。使用项目&gt;属性&gt;调试&gt;启动外部程序单选按钮。选择已编译的VB6程序或VB6 IDE。强制调试器在第一次机会异常时停止,在VS2015中使用Debug&gt; Windows&gt;例外设置和勾选&#34;公共语言运行时异常&#34;。

请注意,此机制对您在自己的工作线程上运行的任何代码都不起作用。在互操作场景中处理那些是很棘手的。据推测,是什么让你对这个问题感到困惑;有时它会起作用#34;场景。

使用SetUnhandledExceptionFilter()非常小心,很容易破坏.NET代码。 CLR也调用该函数来安装自己的处理程序并使用它来引发一些异常。值得注意的是NullReferenceException和DivideByZeroException,这是C#代码可能想要捕获自己的异常。也是非常糟糕的东西,比如AccessViolationException,你永远不想抓住它。它也可能会干扰VB6错误,运行时也会使用SEH来引发异常。

答案 1 :(得分:0)

(这只是一个评论,特别是因为它主要是将我的评论扩展到描述新问题的问题,但它变得太大了。)

我至少在发布版本中使用普通的.NET控制台应用程序重现了我在所有版本中看到的问题(即使在重置我的Visual Studio设置等*之后)禁止模块负载(仅管理)上的JIT优化“关闭并且”仅我的代码“开启。显然,这几乎是一个完全非调试的运行,它在这里警告说,由于符号尚未加载,因此不会触发断点。

(实际上,我后来注意到这个失败 在立即窗口中记录,其中提到了“只是我的代码”。我确实看到调试输出大多数并且肯定关闭重定向到立即窗口选项,但是它会被重置为ON,所以我最初错过了它。)

这让我注意到,在其当前状态下,我的有问题的解决方案的断点现在显示在运行时添加或启用时的感叹号三角形,但不会单独执行它,就像它们用于新.NET一样。只有项目。

(*)重新启动,重置我的设置,修复我的安装并删除我的.suo文件没有帮助。

我还没有明确指出的一点是,对于有问题的解决方案,我以管理员身份运行VS2015(在Windows 10 64位上),因为它需要在编译结束时为COM注册程序集。当然,在发现任何这些调试问题之前,我总是需要这个要求。

我会在某个阶段尝试在Win10 32位笔记本电脑上进行调试,看看有多少是可重复的。