1

i designed an async socket client, after connection i evoke this OnConnect routine.

The goal is to set a status text in the Main window to "connected" and then show a login dialog to the user

Friend Sub OnConnect(ByVal ar As IAsyncResult)
        Try
            oSocket.EndConnect(ar)
            MainDialog.SetStatus("Connected") <-- this line is giving the error

            'We are connected so start listening for messages
            byteData = New Byte(1023) {}
            'Start listening to the data asynchronously
            oSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), Nothing)
            '// show login dialog
            loginDlg = New LoginDialog
            loginDlg.ShowDialog()
        Catch ex As Exception
            ShowMessage(String.Format(My.Resources.error_failed_reason, "connect", "server", ex.Message), MessageBoxIcon.Information)
        End Try
    End Sub

but i get an exception

An error occurred creating the form. See Exception.InnerException for details. The error is: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.

I am not using any thread , just async socket

what could be causing this error? is the OnConnect invoked in another thread?

EDIT

I just made my application single thread by adding this

Public Class Program
    <STAThread()> _
    Shared Sub Main()
        Dim frm As New MainDialog
        Application.Run(frm)
    End Sub
End Class

EDIT 2

I replaced this line

MainDialog.SetStatus("Connected")

With this line

If MainDialog.InvokeRequired Then  <-- This line gives the same error as above
    MainDialog.Invoke(New LoginDelegate(AddressOf ShowLogin), "Connected")
End If

I created this delegate in the module above

Private Delegate Sub LoginDelegate(ByVal Item As Object)
Smith
  • 5,765
  • 17
  • 102
  • 161
  • At what exact line are you getting the exception? – bokibeg Mar 16 '15 at 11:31
  • 1
    at this line `MainDialog.SetStatus("Connected") <-- this line is giving the error` – Smith Mar 16 '15 at 11:32
  • I re-read the question now, I missed it at first :). You just need to set the `STAThread` attribute like Lajos suggested and it should work fine. Tell us if it doesn't fix the prob. It could be that event is fired from another thread in which case you need a diff. solution. – bokibeg Mar 16 '15 at 11:36
  • Check `InnerException` property to see what it says. Your updated code shouldn't throw this exception AFAICT. If you prepare a [short but complete sample](http://stackoverflow.com/help/mcve) demonstrating the problem, It will be helpful. – Sriram Sakthivel Mar 16 '15 at 12:13
  • the errors are the same – Smith Mar 16 '15 at 12:21

3 Answers3

2

You shouldn't update the UI in worker thread. Neither MainDialog.SetStatus nor loginDlg.ShowDialog is a valid thing to do in worker thread.

Ideally you should be calling it in UI thread. You'll do it by calling Control.Invoke or Control.BeginInvoke.

Refer How to update the GUI from another thread in C#?

Community
  • 1
  • 1
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • @Smith It doesn't matter. Async I/O callback will be invoked in worker thread. It will be called in IO completion thread. You need to pass the control to UI thread via Control.Invoke or Control.BeginInvoke – Sriram Sakthivel Mar 16 '15 at 11:39
  • @Smith It seems that the event is being fired from another thread - even if it **was** STA you would still get a cross thread operation exception due to lack of `BeginInvoke`. – bokibeg Mar 16 '15 at 11:41
  • i have replaced the `MainDialog.SetStatus("Connected")` with this `If MainDialog.InvokeRequired Then MainDialog.Invoke(New LoginDelegate(AddressOf ShowLogin), "Connected") End If` but i still get the error – Smith Mar 16 '15 at 11:55
  • @Smith Which line you get the error now, what error same or different? and in which line? post the updated code, so that we can see what you're doing wrong. – Sriram Sakthivel Mar 16 '15 at 11:57
0

You need to use the STAThread attribute (read more here). Note, that you are using a thread, your main thread. If you didn't use a thread, you would not be able to run your program.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
0

I was able to solve my problem myself, what i did was to moved the code to the MainDialog form.

It seems the maindialog.invoke cannot be called from another thread other that the UI thread

Smith
  • 5,765
  • 17
  • 102
  • 161