Splash screen causing cross threading exception if startup form closed from code

0

I've just inherited a legacy VB.Net project which runs fine in VS Community 2017 on a machine on the client's network, but when I try and run the code locally (on VS2017 Pro) I get an exception.

The project has the following properties set:

  • Splash screen: SplashInvoice
  • Startup form: SetupWizard

The code in SetupWizard form's load event checks a few thing and then closes itself if they are OK and opens another form:

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

I'm getting this error when execution exits the SetupWizard_Load if the conditions are met and me.close is called:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll Cross-thread operation not valid: Control 'SplashInvoice' accessed from a thread other than the thread it was created on.

If I comment out the me.close bit it all works fine.

So, it seems like closing the project's startup form while the project's splash screen is still showing is the issue, which leads to a couple of questions:

  • Why does that cause an exception - isn't this all running on the main thread of execution?
  • Why is this happening on my machine, but not on the dev machine?

This is the full stack trace:

System.Transactions Critical: 0 : http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/UnhandledUnhandled exceptionInvoice Generator.exeSystem.InvalidOperationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Cross-thread operation not valid: Control 'SplashInvoice' accessed from a thread other than the thread it was created on. at System.Windows.Forms.Control.get_Handle() at System.Windows.Forms.Form.Activate() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(Object sender, EventArgs e) at System.EventHandler.Invoke(Object sender, EventArgs e) at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)System.InvalidOperationException: Cross-thread operation not valid: Control 'SplashInvoice' accessed from a thread other than the thread it was created on. at System.Windows.Forms.Control.get_Handle() at System.Windows.Forms.Form.Activate() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(Object sender, EventArgs e) at System.EventHandler.Invoke(Object sender, EventArgs e) at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll Cross-thread operation not valid: Control 'SplashTest' accessed from a thread other than the thread it was created on.

The program '[50096] Invoice Generator.exe' has exited with code -1 (0xffffffff).

vb.net
winforms
splash-screen
asked on Stack Overflow Jan 31, 2019 by tomRedox • edited Jan 31, 2019 by tomRedox

1 Answer

0

Before really understanding what was going on here I did manage to stop the exception by manually closing the splash screen in the start up form's Load event. I added a call to the following method into that event:

private sub CloseSplash()

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

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

End sub

That code is based on this answer.

@TnTinMn then provided some really useful information on all of this the comments and led to me to the Microsoft documentation on Extending the Visual Basic Application Model

That has this excellent diagram to explain how it all wires together:

Visual Basic Application Model with SplashScreen

That article also states

ShowSplashScreen. Determines if the application has a splash screen defined and if it does, displays the splash screen on a separate thread.

Which appears to the be root of the issue I'm seeing.

@TnMinMn also made some really useful suggestions on how to fix this issue:

Personally, I would disable the Application Framework and use a Sub Main to launch a customized version of Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase. That way you could set the MainForm based on your some conditions, while still utilizing the base splash screen support, instead of creating a form that never shows when some conditions is true

answered on Stack Overflow Jan 31, 2019 by tomRedox • edited Feb 25, 2019 by tomRedox

User contributions licensed under CC BY-SA 3.0