Windows.Forms Application.Run()中无法执行的异常

时间:2013-01-22 15:28:12

标签: c# winforms debugging visual-studio-2008 exception

我有一个旧的Windows.Forms应用程序,我正在尝试调试。

有时在运行几分钟后会产生ArithmeticException或OverflowException。源必须位于代码库中的某个位置,但堆栈跟踪始终指向行Application.Run(mainForm);

StackTrace没用,因为它只显示Windows.Forms本机调用:

 bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   bei System.Windows.Forms.Application.Run(Form mainForm)
   bei Program.Main() in C:\xy\Program.cs:Zeile 102.

为了找到异常的来源,我已经添加了一个异常处理程序 System.Windows.Forms.Application.ThreadExceptionSystem.AppDomain.CurrentDomain.UnhandledException

我尝试过启用和禁用捕获异常 System.Windows.Forms.Application.SetUnhandledExceptionMode();

永远不会调用ThreadException事件处理程序。 UnhandledException事件处理程序只报告我在Visual Studio中看到的相同异常。

在Visual Studio中,我在抛出异常时启用了中断执行: enter image description here 这没有任何效果。

我该怎么做才能找到有问题的代码行?


编辑:完整的异常详情:

enter image description here


如果我在没有附加任何调试器的情况下启动进程,并在连接调试器之前等待它崩溃,我会得到以下异常:

Unbehandelte Ausnahme bei 0x0c9f9e1b in program.exe: 0xC0000090: Floating-point invalid operation.

调试然后导致这个反汇编

0C9F9E12  add         esi,10h 
0C9F9E15  push        0CA1FD48h 
0C9F9E1A  push        eax  
0C9F9E1B  fmul        qword ptr ds:[0CA202E0h] 
0C9F9E21  fstp        dword ptr [esp+18h] 

我无法解析这个,但我怀疑这只是DispatchMessageW函数

1 个答案:

答案 0 :(得分:7)

这里的诊断是你的进程中有遗留的非托管代码,从你发布的调用堆栈来判断它可能是一个旧的ActiveX控件。

这些例外是FPU(浮点处理器)生成的硬件异常。可以通过引发异常来报告问题的操作模式,例如您看到的STATUS_FLOAT_OVERFLOW和STATUS_FLOAT_INVALID_OPERATION异常。而不是生成无穷大,NaN或非正规。 FMUL指令很容易产生这样的异常。

更改FPU操作模式的软件与托管代码基本上不兼容。这要求FPU异常始终被屏蔽。掩盖这些异常是完全正常的,所有现代软件都可以完成。早在上个世纪,这些例外被认为是诊断浮点计算失败的一项资产。特别是,旧的Borland运行时库揭露了这些异常。

嗯,如果你还没有得到那条消息,这都是一个坏消息。首先要看的是尝试诊断此代码抛出浮点异常的原因。不良数据往往是最常见的原因。其次,你真的必须对FPU控制寄存器进行更改,这很容易导致托管代码失败。特别是WPF代码中的问题,它喜欢使用NaN。

使用调试器查找此类代码非常简单。使用Debug + Windows + Registers调试器窗口。右键单击窗口并勾选“浮点”选项。 CTRL寄存器的值至关重要,在托管程序中应为027F。逐步完成程序,粗略的是,当寄存器发生变化时,你找到了麻烦制造者。如果是64位程序,则也勾选“SSE”,MXCSR寄存器应为00001F80

您无法使用托管代码直接重置FPU控制寄存器,但您可以使用技巧。只要处理异常,CLR就会重置它。所以可能的修复是在导致控制寄存器值改变的语句之后有意抛出并捕获异常:

        try {  throw new Exception("Resetting FPU control register, please ignore"); }
        catch { }

在msvcrt.dll中对_controlfp()函数进行Pinvoking是一种更直接的方法。但是当然,由于两者的副作用现在该库正在以不是为其设计的模式运行,它当然不会期望遇到Nan和Infinity值。从长远来看,你真的需要考虑淘汰旧的组件或库。

相关问题