未处理的异常未被AppDomain.UnhandledException捕获

Mar*_*urd 2 .net vb6 multithreading 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)
Run Code Online (Sandbox Code Playgroud)

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

在由VB6代码创建的第一个.NET对象的构造函数中,我添加了一个处理程序AppDomain.CurrentDomain.UnhandledException(并且,为了调试此问题,我添加了一个for Windows.Forms.Application.ThreadException,但它没有帮助,不是我们有任何无论如何,由.NET显示的UI).

我确信UnhandledException在VS2008中开发此代码时事件已经抓住了,但我不确定我是否已在VS2015中看到过它.

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

执行主要目的的人是:

taskThread = New Thread(AddressOf EnsureTaskCompletes)
taskThread.SetApartmentState(Threading.ApartmentState.STA)
taskThread.Start()
Run Code Online (Sandbox Code Playgroud)

向你展示更多的代码是太专有和复杂了,但我在调试这个问题的同时调整了代码,而Throw New Exception不是最终具有相同效果的复杂代码.(*)

这个"简单"的异常没有被处理过,UnhandledExceptionHandler并且只是默默地终止了程序,除了我打开了非托管调试.

AppDomain.CurrentDomain.UnhandledException当.NET Framework"仅"作为dll加载时,是否存在记录的更改行为?

(因为COM重新注册的,我不想打造VS2008以前的版本尚未确认有一个行为改变.我已经确认了.NET 3.5 的Exe由创建一个VS2015编译Thread抛出未处理的异常处理UnhandledException事件中的例外情况.)

对我来说,解决方法是在已经尝试至少记录线程在任务完成之前终止Catch的现有项Try Finally中添加一个EnusreTaskCompletes,并调用UnhandledExceptionHandler自己.

(*实际问题是数据库中缺少一个表,只有当你用完信用时才使用 - 我没有添加那个代码或表.这引发了一个未被捕获的异常UnhandledExceptionHandler,使它成为相当难以调试 - SQL Server Profiler终于找到了问题.)

Han*_*ant 5

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

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事件来记录详细信息.

调试这样的异常很容易.使用项目>属性>调试>启动外部程序单选按钮.选择已编译的VB6程序或VB6 IDE.强制调试器在第一次机会异常时停止,在VS2015中使用Debug> Windows> Exception Settings并勾选"Common Language Runtime exceptions".

请注意,此机制对您在自己的工作线程上运行的任何代码都不起作用.在互操作场景中处理那些是很棘手的.据推测,这让你对"有时它有效"的情景感到困惑.

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