【问题标题】:Splash screen causing cross threading exception if startup form closed from code如果启动表单从代码中关闭,则启动画面会导致跨线程异常
【发布时间】:2019-06-24 23:40:08
【问题描述】:

我刚刚继承了一个遗留的 VB.Net 项目,该项目在 VS Community 2017 中在客户端网络上的机器上运行良好,但是当我尝试在本地(在 VS2017 Pro 上)运行代码时出现异常。

该项目具有以下属性集:

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

SetupWizard 表单的加载事件中的代码会检查一些东西,如果它们正常则自行关闭并打开另一个表单:

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

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

“System.InvalidOperationException”类型的未处理异常 System.Windows.Forms.dll 中发生的跨线程操作无效: 控制从线程以外的线程访问的“SplashInvoice” 创建于。

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

因此,似乎在项目的启动画面仍然显示时关闭项目的启动表单是问题所在,这导致了几个问题:

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

这是完整的堆栈跟踪:

System.Transactions 严重:0:http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/UnhandledUnhandled 异常发票 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(对象 发件人,EventArgs e)在 System.EventHandler.Invoke(对象发件人, EventArgs e) 在 System.Windows.Forms.Form.OnLoad(EventArgs e) 在 System.Windows.Forms.Form.OnCreateControl() 在 System.Windows.Forms.Control.CreateControl(布尔 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(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息& m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)System.InvalidOperationException: 跨线程操作无效:从 除了创建它的线程之外的线程。在 System.Windows.Forms.Control.get_Handle() 在 System.Windows.Forms.Form.Activate() 在 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen() 在 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(对象 发件人,EventArgs e)在 System.EventHandler.Invoke(对象发件人, EventArgs e) 在 System.Windows.Forms.Form.OnLoad(EventArgs e) 在 System.Windows.Forms.Form.OnCreateControl() 在 System.Windows.Forms.Control.CreateControl(布尔 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(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息& 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)。

【问题讨论】:

  • 在程序启动过程中启动画面是否以任何方式更新?你能提供异常的堆栈跟踪吗?
  • 尝试在没有启动画面的情况下运行项目。您仍然收到错误消息吗?
  • @ChrisDunaway 我已经更新了问题以包含跟踪。当我添加一个没有代码的新启动屏幕时,我也会收到错误消息。我已经搜索了代码,但没有提到我的新启动画面。有什么方法可以引用当前的初始屏幕而不涉及通过名称调用它?
  • @preciousbetine,对不起,本来应该这么说的,没有闪屏就没有错误
  • 堆栈跟踪表明异常发生在名为MainFormLoadingDone 的方法中,当它调用另一个名为HideSplashScreen 的方法时。这些方法中的任何一个是否在不同的线程上运行?

标签: vb.net winforms splash-screen


【解决方案1】:

在真正了解这里发生了什么之前,我确实设法通过手动关闭启动表单的 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 然后提供了关于所有这些 cmets 的一些非常有用的信息,并引导我访问Extending the Visual Basic Application Model 上的 Microsoft 文档

这有一个很好的图表来解释它是如何连接在一起的:

那篇文章还说

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    • 1970-01-01
    相关资源
    最近更新 更多