我在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,则会触发Catch ex As Exception
内的Wrapper()
(这是预期的结果)。这有什么不对?
Visual Studio错误消息为An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in filename.exe
。
这是在调用MyForm.Show()
期间发生的,它间接调用MyForm_Load()
事件处理程序并调用MyComboBox_SelectedIndexChanged()
事件处理程序(这个间接执行查询)。
如果我在中断期间找到并点击Wrapper()
堆叠框架,我可以看到位于FillMyDataTable()
/ Try
之间的Catch
被忽略的电话。< / p>
我总是在主线程上(ManagedThreadId
存储Startup
事件,然后多个断言验证它是否插入上面的代码中。
堆栈跟踪完全相同(通过差异检查),除了最底部的框架(System.Windows.Forms.NativeWindow.DebuggableCallback()
与System.Windows.Forms.NativeWindow.Callback()
)。
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
。直到昨天才出现问题。我想我已经改变了一些选择。
重启Visual Studio没有帮助。
如果启用或禁用了异常助手,则行为没有变化。
选项和例外设置如下:
堆栈跟踪是:
myApp.exe!myApp.frmAPP_PrenosWizard.frmFT_PrenosWizard_Load(Object sender, System.EventArgs e) Line 125 Basic System.Windows.Forms.dll!System.Windows.Forms.Form.OnLoad(System.EventArgs e) + 0x1d5 bytes System.Windows.Forms.dll!System.Windows.Forms.Form.OnCreateControl() + 0x55 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.CreateControl(bool fIgnoreVisible) + 0x181 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.CreateControl() + 0x24 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.WmShowWindow(ref System.Windows.Forms.Message m) + 0x98 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x2b6 bytes System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) + 0x2a bytes System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.WndProc(ref System.Windows.Forms.Message m) + 0x10 bytes System.Windows.Forms.dll!System.Windows.Forms.Form.WmShowWindow(ref System.Windows.Forms.Message m) + 0x41 bytes System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) + 0x154 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x10 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x57 bytes [Native to Managed Transition] [Managed to Native Transition] 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, object pvParam) + 0x3c bytes System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(System.Windows.Forms.CreateParams cp) + 0x225 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.CreateHandle() + 0x125 bytes System.Windows.Forms.dll!System.Windows.Forms.Form.CreateHandle() + 0x9f bytes System.Windows.Forms.dll!System.Windows.Forms.Control.Handle.get() + 0x45 bytes System.Windows.Forms.dll!System.Windows.Forms.Form.SetVisibleCore(bool value) + 0x160 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.Show() + 0x10 bytes myApp.exe!myApp.APP.clsPrenos.ZobrazWizard(myApp.frmAPP_PrenosWizard.enRezimPrenosu rezim, myApp.APP.clsEntita.enEntita zdrojEntita, Integer zdrojID, myApp.APP.clsEntita.enEntita cielEntita, Integer cielID, System.Data.SqlClient.SqlConnection cn1) Line 8212 + 0xa bytes Basic myApp.exe!myApp.frmMain.FCreateTransferUI(myApp.frmAPP_PrenosWizard.enRezimPrenosu mode, myApp.APP.clsEntita.enEntita sourceEntity, Integer sourceID, myApp.APP.clsEntita.enEntita targetEntity, Integer targetID, System.Data.SqlClient.SqlConnection cn1) Line 2410 + 0x17 bytes Basic myApp.exe!myApp.frmMain.frmMain_Receive(Object sender, myApp.clsFisCommandProcessor.ReceivedEventArgs e) Line 239 + 0xa7 bytes Basic myApp.exe!myApp.clsFisCommandProcessor.raise_Received(Object sender, myApp.clsFisCommandProcessor.ReceivedEventArgs e) Line 96 + 0x2e bytes Basic 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) Line 94 + 0x51 bytes Basic 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 bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.HandleClick(System.EventArgs e) + 0x6e bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.FireEventInteractive(System.EventArgs e, System.Windows.Forms.ToolStripItemEventType met) + 0x83 bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.FireEvent(System.EventArgs e, System.Windows.Forms.ToolStripItemEventType met) + 0x118 bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripMenuItem.ProcessCmdKey(ref System.Windows.Forms.Message m, System.Windows.Forms.Keys keyData) + 0x47 bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripManager.ProcessShortcut(ref System.Windows.Forms.Message m, System.Windows.Forms.Keys shortcut) + 0x2dc bytes System.Windows.Forms.dll!System.Windows.Forms.ToolStripManager.ProcessCmdKey(ref System.Windows.Forms.Message m, System.Windows.Forms.Keys keyData) + 0x2d bytes System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0x3c bytes System.Windows.Forms.dll!System.Windows.Forms.Form.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0x29 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0x96 bytes System.Windows.Forms.dll!System.Windows.Forms.TextBoxBase.ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) + 0xda bytes System.Windows.Forms.dll!System.Windows.Forms.Control.PreProcessMessage(ref System.Windows.Forms.Message msg) + 0x90 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.PreProcessControlMessageInternal(System.Windows.Forms.Control target, ref System.Windows.Forms.Message msg) + 0x101 bytes System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(ref System.Windows.Forms.NativeMethods.MSG msg) + 0xf6 bytes System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FPreTranslateMessage(ref System.Windows.Forms.NativeMethods.MSG msg) + 0x5 bytes System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason, int pvLoopData) + 0x22e bytes System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x177 bytes 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 context) + 0x18 bytes Microsoft.VisualBasic.dll!Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() + 0x81 bytes Microsoft.VisualBasic.dll!Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() + 0xef bytes Microsoft.VisualBasic.dll!Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(string[] commandLine) + 0x68 bytes [Native to Managed Transition] [Managed to Native Transition] mscorlib.dll!System.AppDomain.nExecuteAssembly(System.Reflection.Assembly assembly, string[] args) + 0x19 bytes mscorlib.dll!System.Runtime.Hosting.ManifestRunner.Run(bool checkAptModel) + 0x6e bytes mscorlib.dll!System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly() + 0x84 bytes 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 bytes mscorlib.dll!System.Activator.CreateInstance(System.ActivationContext activationContext) + 0x3e bytes Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone() + 0x23 bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x66 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes
答案 0 :(得分:3)
这个问题有许多可动的部分,不确定我能否对所有这些部分公正。起点是,如果使用调试器,则不应订阅这些事件。用If Not System.Diagnostics.Debugger.IsAttached Then
包裹该代码,以便您可以正确诊断和修复未处理的异常。
重要的随机化器是在Load事件处理程序中抛出的异常会发生的事情。 Microsoft在正确处理Windows回调处于活动状态时引发的异常时遇到了很多麻烦。例如导致Load事件触发的那个。他们再次在Win8上再次在Win7上更改了Vista的规则。如果运行64位版本的32位,它们会有所不同。以及您的程序是以32位还是64位进程运行。使用调试器会改变行为。异常发生时可能会出现程序兼容性助手,询问您是否希望程序“兼容”。每个人都说是的,这是一个非常糟糕的主意。添加它们,您可以获得 32个不同结果之一。哎哟。
它在this MSDN article中正式描述,但没有人理解它。直到它没有做他们希望的事情,在问题like this one中提到。缓解情况是,在调试应用程序时,这只是字节,消息循环中的正常异常后退可确保在用户的计算机上不会失控。换句话说,当您按下Ctrl + F5或使用资源管理器运行程序时所看到的内容就是您希望它工作的方式。
这是影响Windows上任何 GUI程序的问题。但它在Winforms应用程序中具有特别麻烦的诀窍,程序员完全使用Load事件。由于它是Form类的默认事件而被删除,只需双击即可生成它。特别是在VB.NET中,它不会自动为表单创建构造函数,Visual Basic有使用Load事件初始化表单的遗留问题,返回VB6。
我通常会避免判断我看到的编程实践,但是由于这些问题,今天使用Load事件是一种非常糟糕的做法。总是喜欢构造函数初始化一个类,这是任何.NET程序员都知道的规则,对于Form类来说它没有什么不同。 拥有使用Load的原因极少,this post中涵盖了。