【问题标题】:Inside Try/Catch, Visual Studio breaks and ends app on Unhandled exception在 Try/Catch 中,Visual Studio 在未处理的异常上中断并结束应用程序
【发布时间】:2015-05-01 03:08:46
【问题描述】:

在 Visual Studio 内部和外部运行相同的代码时,我会遇到不同的行为。

Private Sub MyApplication_Startup(...) Handles Me.Startup
    '--- handler for unhandled exceptions
    AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledExHandler
    '--- handler 0
    AddHandler System.Windows.Forms.Application.ThreadException, AddressOf ThreadExHandler
    Utils.RememberMainThreadId()
End Sub

Sub OpenMyForm()  'entry point
    Debug.Assert(Utils.RunningOnMainThread())
    Try
        MyForm.Show()  
    Catch ex As Exception  '--- handler 1
        LogError(ex)   '--- goes here only if launched outside the Visual Studio
    End Try
End Sub

Sub MyForm_Load() Handles MyBase.Load
    Debug.Assert(Utils.RunningOnMainThread())
    FillMyDataTable() '---if I put try/catch here, it will always work (tested)
End Sub

Sub FillMyDataTable()
    Try
        New SqlClient.SqlDataAdapter(sqlCmd).Fill(myDataTable)
    Catch ex As Exception '--- handler 2
        If ex.Number = Constants.ConnectionBroken then
            ReconnectRetry()
        Else
            Throw  '--- enters UnhandledExHandler() when in Visual Studio
        End If
    End Try
End Sub

在 Visual Studio 中,错误 SQL 命令中的错误转到 UnhandledExHandler(), 但如果在 VS 外部启动相同的 EXE,则会触发 Wrapper() 内的 Catch ex As Exception(这是预期结果)。这里有什么问题?

  • Visual Studio 错误消息是An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in filename.exe

  • 这发生在调用MyForm.Show() 的过程中,它间接调用MyForm_Load() 事件处理程序并调用MyComboBox_SelectedIndexChanged() 事件处理程序(并且这个间接执行查询)。

  • 如果我在异常中断期间找到并单击 Wrapper() 堆栈帧,我可以看到位于 Try/Catch 之间的对 FillMyDataTable() 的高亮调用。

  • 我总是在主线程上(ManagedThreadId 存储在Startup 事件期间,然后在上面的代码中插入了多个验证它的断言)。

  • 除了最底部的帧(System.Windows.Forms.NativeWindow.DebuggableCallback()System.Windows.Forms.NativeWindow.Callback())之外,堆栈跟踪完全相同(通过 diff 检查)。

    • 最上面的框架是System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
  • 直到昨天才出现这个问题。我想我改变了一些选项。

  • 重新启动 Visual Studio 没有帮助。

  • 如果启用或禁用异常助手,行为不会发生变化。

  • 选项和异常设置如下:

  • 堆栈跟踪是:

myApp.exe!myApp.frmAPP_PrenosWizard.frmFT_PrenosWizard_Load(Object sender, System.EventArgs e) 第 125 行基本 System.Windows.Forms.dll!System.Windows.Forms.Form.OnLoad(System.EventArgs e) + 0x1d5 字节 System.Windows.Forms.dll!System.Windows.Forms.Form.OnCreateControl() + 0x55 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.CreateControl(bool fIgnoreVisible) + 0x181 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.CreateControl() + 0x24 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.WmShowWindow(ref System.Windows.Forms.Message m) + 0x98 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x2b6 字节 System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) + 0x2a 字节 System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.WndProc(ref System.Windows.Forms.Message m) + 0x10 字节 System.Windows.Forms.dll!System.Windows.Forms.Form.WmShowWindow(ref System.Windows.Forms.Message m) + 0x41 字节 System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) + 0x154 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x10 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 字节 System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x57 字节 [本机到托管转换] [管理到本地转换] System.Windows.Forms.dll!System.Windows.Forms.UnsafeNativeMethods.CreateWindowEx(int dwExStyle, string lpszClassName, string lpszWindowName, int style, int x, int y, int width, int height, System.Runtime.InteropServices.HandleRef hWndParent , System.Runtime.InteropServices.HandleRef hMenu, System.Runtime.InteropServices.HandleRef hInst, 对象 pvParam) + 0x3c 字节 System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(System.Windows.Forms.CreateParams cp) + 0x225 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.CreateHandle() + 0x125 字节 System.Windows.Forms.dll!System.Windows.Forms.Form.CreateHandle() + 0x9f 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.Handle.get() + 0x45 字节 System.Windows.Forms.dll!System.Windows.Forms.Form.SetVisibleCore(bool value) + 0x160 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.Show() + 0x10 字节 myApp.exe!myApp.APP.clsPrenos.ZobrazWizard(myApp.frmAPP_PrenosWizard.enRezimPrenosu rezim,myApp.APP.clsEntita.enEntita zdrojEntita,整数 zdrojID,myApp.APP.clsEntita.enEntita cielEntita,整数 cielID,System.Data.SqlClient.SqlConnection cn1) 第 8212 行 + 0xa 字节基本 myApp.exe!myApp.frmMain.FCreateTransferUI(myApp.frmAPP_PrenosWizard.enRezimPrenosu 模式, myApp.APP.clsEntita.enEntita sourceEntity, Integer sourceID, myApp.APP.clsEntita.enEntita targetEntity, Integer targetID, System.Data.SqlClient.SqlConnection cn1)第 2410 行 + 0x17 字节基本 myApp.exe!myApp.frmMain.frmMain_Receive(Object sender, myApp.clsFisCommandProcessor.ReceivedEventArgs e) 第 239 行 + 0xa7 字节基本 myApp.exe!myApp.clsFisCommandProcessor.raise_Received(Object sender, myApp.clsFisCommandProcessor.ReceivedEventArgs e) 第 96 行 + 0x2e 字节基本 myApp.exe!myApp.clsFisCommandProcessor.Execute(myApp.clsFisCommand command, Object sender) Line 136 + 0x57 bytes Basic myApp.exe!myApp.clsFisCommandProcessor.Execute(myApp.clsFisCommand() commands, Object sender) Line 128 + 0x27 bytes Basic myApp.exe!myApp.clsFisCommandProcessor.Execute(String scan, Boolean requireMarking, Object sender) Line 122 + 0x30 bytes Basic myApp.exe!myApp.frmCommandPad.TSMI_Execute_Click(Object sender, System.EventArgs e) 第 94 行 + 0x51 字节基本 System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.RaiseEvent(object key, System.EventArgs e) + 0x58 bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripMenuItem.OnClick(System.EventArgs e) + 0x46 字节 System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.HandleClick(System.EventArgs e) + 0x6e 字节 System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.FireEventInteractive(System.EventArgs e, System.Windows.Forms.ToolStripItemEventType) + 0x83 字节 System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.FireEvent(System.EventArgs e, System.Windows.Forms.ToolStripItemEventType) + 0x118 字节 System.Windows.Forms.dll!System.Windows.Forms.ToolStripMenuItem.ProcessCmdKey(ref System.Windows.Forms.Message m, System.Windows.Forms.Keys keyData) + 0x47 字节 System.Windows.Forms.dll!System.Windows.Forms.ToolStripManager.ProcessShortcut(参考 System.Windows.Forms.Message m,System.Windows.Forms.Keys 快捷方式)+ 0x2dc 字节 System.Windows.Forms.dll!System.Windows.Forms.ToolStripManager.ProcessCmdKey(ref System.Windows.Forms.Message m, System.Windows.Forms.Keys keyData) + 0x2d 字节 System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0x3c 字节 System.Windows.Forms.dll!System.Windows.Forms.Form.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0x29 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0x96 字节 System.Windows.Forms.dll!System.Windows.Forms.TextBoxBase.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0xda 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.PreProcessMessage(ref System.Windows.Forms.Message msg) + 0x90 字节 System.Windows.Forms.dll!System.Windows.Forms.Control.PreProcessControlMessageInternal(System.Windows.Forms.Control 目标,参考 System.Windows.Forms.Message msg) + 0x101 字节 System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(ref System.Windows.Forms.NativeMethods.MSG msg) + 0xf6 字节 System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FPreTranslateMessage(参考 System.Windows.Forms.NativeMethods.MSG msg)+ 0x5 字节 System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason, int pvLoopData) + 0x22e 字节 System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x177 字节 System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x61 bytes System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.ApplicationContext 上下文) + 0x18 字节 Microsoft.VisualBasic.dll!Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() + 0x81 字节 Microsoft.VisualBasic.dll!Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() + 0xef 字节 Microsoft.VisualBasic.dll!Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(string[] commandLine) + 0x68 字节 [本机到托管转换] [管理到本地转换] mscorlib.dll!System.AppDomain.nExecuteAssembly(System.Reflection.Assembly 程序集,string[] args) + 0x19 字节 mscorlib.dll!System.Runtime.Hosting.ManifestRunner.Run(bool checkAptModel) + 0x6e 字节 mscorlib.dll!System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly() + 0x84 字节 mscorlib.dll!System.Runtime.Hosting.ApplicationActivator.CreateInstance(System.ActivationContext activationContext, string[] activationCustomData) + 0x65 bytes mscorlib.dll!System.Runtime.Hosting.ApplicationActivator.CreateInstance(System.ActivationContext activationContext) + 0xa 字节 mscorlib.dll!System.Activator.CreateInstance(System.ActivationContext activationContext) + 0x3e 字节 Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone() + 0x23 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(对象状态)+ 0x66 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback 回调, 对象状态) + 0x6f 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 字节

【问题讨论】:

  • 什么是异常堆栈跟踪?例如。如果LogError 在附加调试器时抛出异常,而不是在LogError 中看到带有堆栈跟踪的异常
  • 这是预期的(功能)如果您检查了 CLR 异常的“抛出”复选框是否有足够的异常。你确定你已经发布了设置吗?
  • 这完全是故意的,当您使用调试器时会故意禁用 Application.ThreadException 事件。让您轻松诊断和修复异常非常重要。您应该只在 Debugger.IsAttached 为 False 时注册这些事件处理程序。
  • @HansPassant – 如果您提到 Application.ThreadException 事件,我知道您在评论 Handler 0(请参阅更新的代码)。谢谢你的意见。但在这种情况下,Handler 1 没有捕捉到任何东西——这就是问题所在。异常不能通过Form.Show() 冒泡。
  • If 只能捕获构造函数中发生的异常。这是永远不会的。如果您的 Load 事件在构造函数尚未完成时触发,那么您有一个需要解决的问题。在 Load 事件上设置断点并查看调用堆栈。最好的办法是使用 Load 事件,将代码放在那里毫无意义。它属于构造函数。你也会避开this nasty randomizer

标签: .net visual-studio visual-studio-2012 exception-handling try-catch


【解决方案1】:

这个问题有很多变化的部分,我不确定我是否可以对所有这些部分都公正。起点是,如果您使用调试器,则不应订阅这些事件。用If Not System.Diagnostics.Debugger.IsAttached Then 包装该代码,以便您可以正确诊断和修复未处理的异常。

一个重要的随机化器是在 Load 事件处理程序中抛出的异常会发生什么。 Microsoft 在正确处理 Windows 回调处于活动状态时引发的异常时遇到了很多麻烦。例如导致 Load 事件触发的事件。他们在 Vista、Win7 和 Win8 再次改变了规则。如果运行 32 位和 64 位版本,它们是不同的。以及您的程序是否作为 32 位或 64 位进程运行。使用调试器会改变行为。发生异常时可能会出现程序兼容性助手,询问您是否希望您的程序“兼容”。每个人都说是的,当然,这是一个非常糟糕的主意。将它们相加,您可以获得三十二种种不同的结果之一。哎哟。

它在this MSDN article 中有正式描述,但没有人理解。直到它没有达到他们希望的效果,这在一个问题like this one 中涵盖。缓解情况是,当您调试应用程序时,这仅是字节,消息循环中的正常异常支持确保这不会在您的用户计算机上失控。换句话说,当您按下 Ctrl+F5 或使用 Explorer 运行程序时,您所看到的就是您所期望的工作方式。

这是一个影响Windows 上任何 GUI 程序的问题。但它有一个在 Winforms 应用程序中特别麻烦的诀窍,程序员完全过多地使用 Load 事件。由于它是 Form 类的默认事件,因此它被迷惑了,只需双击即可生成它。尤其是在 VB.NET 中,它不会自动为表单创建构造函数,而 Visual Basic 有使用 Load 事件来初始化表单的传统,这可以追溯到 VB6。

我通常避免评判我看到的编程实践,但由于这些问题,现在使用 Load 事件是一种非常糟糕的实践。总是倾向于使用构造函数来初始化一个类,这是任何 .NET 程序员都知道的规则,Form 类也没有什么不同。 使用 Load 的理由非常少,this post 中对此进行了介绍。

【讨论】:

  • 很好的信息。我会尽量避免如上所述的Load 事件处理程序。只是一个小提示,我没有使用UnhandledExceptionMode.CatchException。所以处理程序只记录一个异常(以避免打印屏幕等的必要性)并退出(=继续崩溃)——即使附加了调试器。
猜你喜欢
  • 2011-01-01
  • 1970-01-01
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多