如果启动表单已从代码中关闭,则启动画面会导致跨线程异常

时间:2019-01-31 13:35:23

标签: vb.net winforms splash-screen

我刚刚继承了一个旧版VB.Net项目,该项目可以在客户端网络上的计算机上的VS Community 2017中正常运行,但是当我尝试在本地(在VS2017 Pro上)运行代码时,会出现异常。

该项目设置了以下属性:

  • 启动画面:SplashInvoice
  • 启动表单:SetupWizard

SetupWizard表单的load事件中的代码检查了几件事,如果确定还可以关闭自身,然后打开另一个表单:

Private Sub SetupWizard_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        If [some conditions] Then
            frmMain.Show()
            Me.Close()
        Else

如果满足条件并调用SetupWizard_Load,则执行退出me.close时出现此错误:

  

类型为'System.InvalidOperationException'的未处理异常   发生在System.Windows.Forms.dll跨线程操作无效:   从其他线程访问的控件“ SplashInvoice”   创建于。

如果我注释掉me.close位,一切正常。

因此,似乎是在项目的启动画面仍显示时关闭项目的启动表单,这引发了两个问题:

  • 为什么会导致异常-这不是全部在主计算机上运行吗 执行线程?
  • 这是为什么在我的机器上发生,但没有发生 开发机器?

这是完整的堆栈跟踪:

  

System.Transactions严重:0:http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled未处理   例外发票   Generator.exeSystem.InvalidOperationException,   mscorlib,版本= 4.0.0.0,文化=中性,   PublicKeyToken = b77a5c561934e089跨线程   操作无效:控件'SplashInvoice'从其他线程访问   比创建它的线程要多。在   System.Windows.Forms.Control.get_Handle()在   System.Windows.Forms.Form.Activate()在   Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen()   在   Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(Object   发送方,System.EventHandler.Invoke处的EventArgs e)(对象发送方,   EventArgs e)位于System.Windows.Forms.Form.OnLoad(EventArgs e)位于   System.Windows.Forms.Form.OnCreateControl()在   System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
  在System.Windows.Forms.Control.CreateControl()在   System.Windows.Forms.Control.WmShowWindow(Message&m)位于   System.Windows.Forms.Control.WndProc(Message&m)位于   System.Windows.Forms.ScrollableControl.WndProc(Message& m)
  在System.Windows.Forms.Form.WmShowWindow(Message&m)处   System.Windows.Forms.Form.WndProc(Message&m)位于   System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&   m)在   System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&   m)在System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr   hWnd,Int32 msg,IntPtr wparam,IntPtr   lparam)System.InvalidOperationException:   跨线程操作无效:从控件访问“ SplashInvoice”   创建线程以外的其他线程。在   System.Windows.Forms.Control.get_Handle()在   System.Windows.Forms.Form.Activate()在   Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen()   在   Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(Object   发送方,System.EventHandler.Invoke处的EventArgs e)(对象发送方,   EventArgs e)位于System.Windows.Forms.Form.OnLoad(EventArgs e)位于   System.Windows.Forms.Form.OnCreateControl()在   System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
  在System.Windows.Forms.Control.CreateControl()在   System.Windows.Forms.Control.WmShowWindow(Message&m)位于   System.Windows.Forms.Control.WndProc(Message&m)位于   System.Windows.Forms.ScrollableControl.WndProc(Message& m)
  在System.Windows.Forms.Form.WmShowWindow(Message&m)处   System.Windows.Forms.Form.WndProc(Message&m)位于   System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&   m)在   System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&   m)在System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr   hWnd,Int32 msg,IntPtr wparam,IntPtr   lparam)未处理   类型“ System.InvalidOperationException”的异常发生在   System.Windows.Forms.dll跨线程操作无效:控件   从不是该线程的线程访问了'SplashTest'   创建于。

     

程序“ [50096] Invoice Generator.exe”已退出,代码为-1   (0xffffffff)。

1 个答案:

答案 0 :(得分:0)

在真正理解这里发生的事情之前,我确实设法通过在启动表单的Load事件中手动关闭了启动屏幕来停止异常。我在该事件中添加了对以下方法的调用:

private sub CloseSplash()

    Dim mySplash = My.Application.OpenForms.Item("SplashInvoice")

    mySplash.Invoke(New MethodInvoker(Sub()
        mySplash.Close()
        mySplash.Dispose()
    End Sub))

End sub

代码is based on this answer

@TnTinMn然后提供了关于所有这些注释的一些非常有用的信息,并带我到Extending the Visual Basic Application Model上的Microsoft文档

该图中有一个很好的图来说明它们如何连接在一起:

Visual Basic Application Model with SplashScreen

该文章还指出

  

ShowSplashScreen。确定应用程序是否具有启动屏幕   已定义,如果已定义,则将启动屏幕显示在单独的屏幕上   线程。

这似乎是我所看到的问题的根源。

@TnMinMn还提出了一些有关如何解决此问题的非常有用的建议:

  

我个人将禁用应用程序框架并使用Sub   主要推出定制版   Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase。   这样,您可以根据自己的条件设置MainForm,   同时仍在使用基本的初始屏幕支持,而不是   创建一个在某些条件为真时永远不会显示的表单