Search code examples
.netvb.netwinformsasynchronoushwnd

Unexpected\false positive error: 'Invoke or BeginInvoke cannot be called on a control until the window handle has been created'


In specific asynchronous circumstances I'm getting a System.Reflection.TargetInvocationException exception with this error message:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created

Please note that THIS IS NOT A DUPLICATE QUESTION, here below I explain why. I am aware of what the error means, but that exception cannot be/should not be thrown, because the handle of the window is created in my code.

I'm starting to think this error message I'm getting could be a new bug in the .NET Framework, I need the help of someone that could clarify whether it is my fault in the code or not my fault, and how to fix this problem.

I just have this class that represents the main application Form:

Public NotInheritable Class Main : Inherits Form

    Private Async Sub ButtonMirror_Click(sender As Object, e As EventArgs) Handles ButtonMirror.Click

        ' Synchronous.
        ' Dim sucess As Boolean = MirrorUtil.BuildMirror

        ' Asynchronous.
        Dim t As Task(Of Boolean) = Task.Run(Of Boolean)(AddressOf MirrorUtil.BuildMirror)
        Dim sucess As Boolean = Await t

    End Sub

End Class

Note that the event-handler has the Async keyword specified.

And this is the BuildMirror method

Friend NotInheritable Class MirrorUtil

    Friend Shared Function BuildMirror() As Boolean
        My.Forms.Main.Invoke(Sub() My.Forms.Main.Visible = False)
    End Function

End Class

The problem is inside the block of the BuildMirror method, and ONLY happens if I call it asynchronously like I'm doing in the code above, the Main.Invoke() method throws the exception mentioned, and if I perform a call to Main.IsHandleCreated it surprisingly returns False! ...only when I call asynchronously the BuildMirror method, I insist.

I would like to understand what is happening, and how to fix it. Of course the main application form is instanced and visible, the window handle is created, then it should not throw that exception...

I found this strange issue while trying to debug the real problem, which is not the problem that I exposed in this question, however I think this strange problem is the cause of my real problem, so I would appreciate a solution for this.


Solution

  • Consider these facts about the problem:

    1. When you call My.Forms.Main in another thread, the form which you get, is not the form which you created and showed in the main thread. It's a new instance of Main. But if you call it in the main thread, it's the existing instance which its handle is created. (My.Forms.Something will return the existing instance for the main form, and for other forms, create a new instance and cache it and use it.)

    2. Calling Invoke method will throw an exception, if the handle of the form is not created and the handle of the form will be created after you show it.

    When you call My.Forms.Main.Invoke(Sub() My.Forms.Main.Visible = False) in another thread, My.Forms.Main will be a new instance, and it's handle is not created, so calling Invoke on it will result the exception which you received.