Question error BeginInvoke cannot be called .. until window handle has been created

champ

New member
Joined
Jan 17, 2014
Messages
3
Programming Experience
10+
VB 2008
I have read posts here and elsewhere online but cannot figure out what the problem is. Please help. FYI, I am new to OOP.

I have 2 (simplified)code files shown below, one with the UI form and one class for the serial port stuff. When the beginInvoke occurs I get the uncreated handle error. If I check for the handle in Form1 in the form load it of course exists and has a value.
If I take all the serPort_cls code and rearrange it so it is part of the Form1 class it works fine. I suspect I am missing something very obvious.

#Region "formFile"

Public Class Form1

Dim sp As New serPort_cls

Public Sub processRcvdData()
' actually do something useful here, msgbox just for testing
MsgBox("data rcvd")
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim h As Integer
If Me.IsHandleCreated Then
h = Handle ' yes, handle does exist, here it is
End If
'Me.CreateHandle()
sp.openCom()

End Sub

End Class
#End Region


#Region "classFile"

Imports System.IO.Ports

Public Class serPort_cls

Private WithEvents serPort As New SerialPort
Delegate Sub UIrcvdDataHandler()

Public Sub openCom()

serPort.PortName = "COM1"
serPort.Open()
serPort.BaudRate = 38400
serPort.ReceivedBytesThreshold = 10 ' set bigger than largest message expected, EOF will trigger DataReceived event

End Sub

Private Sub Receiver(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles serPort.DataReceived

' invoke handler in UI thread
Form1.BeginInvoke(New UIrcvdDataHandler(AddressOf Form1.processRcvdData))
'Form1.beginInvoke(New MethodInvoker(AddressOf Form1.processRcvdData))

' either of the invoke methods above produces the following error
'"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."

End Sub
End Class
#End Region
 
Default form are thread specific, so that will return you a new Form1 instance in DataReceived event handler. You can pass your current form instance (Me) to your class instance and use that with BeginInvoke.
Your class can also define and raise its own event, that the form can listen to and handle invoking itself.
 
Thanks,
I thought it might be an instance/class issue. Which part of the invoke statement is problematic, the Form1.beginInvoke or (AddressOf Form1.processRcvdData)? I still do not know how to "pass" me to the serPort_cls class.
I know me.invoke(...) won't work. If I use me in Receiver() it refers to the serPort_cls class.
Any additional help is greatly appreciated.
 
If you want to be able to marshal a method call to the UI thread in an object that is not UI aware, i.e. not a form or control, then you should use the SynchronizationContext class. You get the instance for the current thread from the Shared Current property when you create the object on the UI thread and you can then call the Send or Post method of that instance to marshal a method call back to the thread that instance was created on, i.e. the UI thread. Here's an example:

Accessing Controls from Worker Threads

Note that that example code is in a form but it doesn't matter what class you put it in as long as the instance of that class is created on the UI thread. Note that Send is synchronous, like Invoke, while Post is asynchronous, like BeginInvoke.
 
Back
Top