System.Threading.ThreadStateException error...?

Hi experts

I am lost when trying to understand why this error is being thrown. I wasn't aware I was using a worker thread in my code. Please could somebody help me understand what is happenning...

I have two forms, called for arguments sake 'Main' and 'Explorer'

When a button is clicked in 'Explorer' it calls a public sub in 'Main' called SendReceive() which executes, as the name suggests, a sendreceive in the outlook namespace. It also sets up a handler for the syncend() event, called private sub SyncEnd(). When this event is called it removes the handler, kills the outlook.exe process then calls a sub in the 'Explorer' form to refresh it's view of the folder.

It's this last call that throws the exception. I am left assuming that the synend handler is being run in a seperate thread. If that is so, how do i call back to the 'Explorer' Form?

See code below.

Any help is appreciated. Thanks in advance.
'
' Main routines
'
Public Sub SendReceive()
	Try
		oApp = New Outlook.Application
		Dim oNS As Outlook._NameSpace = oApp.GetNamespace("mapi")
		Dim oSyncs As Outlook.SyncObjects
		Dim oSync As Outlook.SyncObject
		oNS.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).GetExplorer()
		oSyncs = oNS.SyncObjects
		oSync = oSyncs.Item("All Accounts")
		instance = oSync
		AddHandler instance.SyncEnd, AddressOf SyncEnd
		oSync.Start()
		oNS.Logoff()
		oSync = Nothing
		oSyncs = Nothing
		oNS = Nothing
		oApp = Nothing
	Catch ex As Exception
		MsgBox(ex.ToString)
	End Try
End Sub
 
Private Sub SyncEnd()
	RemoveHandler instance.SyncEnd, AddressOf SyncEnd
	oApp = Nothing
	Dim myProcesses As Process() = Process.GetProcessesByName("outlook")
	For Each myProcess As Process In myProcesses
		If myProcess.MainWindowTitle = "" Then myProcess.Kill()
	Next myProcess
	If Explorer.Visible = True Then Explorer.RefreshItems()
End Sub
 
 
'
' Explorer routines
'
Private Sub SendReceive(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tssendreceive.Click
	main.SendReceive()
End Sub
 
Public Sub RefreshItems()
	Dim session As RDOSession = CreateObject("Redemption.RDOSession")
	session.Logon()
	folderitems = GetMailItemsFromFolder(session.GetFolderFromPath(currentfolder))
	UpdateItems(SelectRows(sortcolumn & " " & sortorder))
	session.Logoff()
End Sub

Open in new window

jeruteAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
wmestromConnect With a Mentor Commented:
Hi,

your right I miss typed. Where I wrote

Public Delegate Sub Refresh()

I meant

Public Delegate Sub RefreshDelegate()

But that doesn't help you I see. From the exception you get it seems that the Explorer thread is in MTA appartment state which doesn't allow the OLE calls you are doing. But this would mean you get the same exception if you call RefreshItems directly from the Explorer.SendReceive method.

If this is the case change the appartment state of the Explorer thread to STA:

thread.SetApartmentState(Threading.ApartmentState.STA)

If you do not start a new thread yourself than add this attribute to your startup method (usually main)

    <STAThread()> _
    Sub Main()
        'Do your stuff
    End Sub

Hope this helps...
0
 
wmestromCommented:
If you like to be certain that the code executes on the same thread as the thread that is associated with a form you can use the Invoke method of the form. Pass the method you want to execute on that thread as a delegate and optionally the parameters it needs.
'A delegate
Public Delegate Sub Refresh()
 
'The explorer form
Dim explorerForm As System.Windows.Forms.Form
 
'Method calling the Refresh method on the explorer form thread
Sub CallExplorerRefreshMethod
  explorerForm.Invoke([Delegate].CreateDelegate(GetType(RefreshDelegate), explorerForm, "Refresh"))
 
End Sub

Open in new window

0
 
jeruteAuthor Commented:
Hi wmestrom

Thanks for your reply but I'm not sure if this would work. I neglected to mention that the explorer form remains open while the sendreceive runs.

Therefore the line 'dim explorerform as system.windows.forms.form' is going to cause a second instance, isn't it?

Jerute
0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
wmestromCommented:
Hi jerute,

it will only create a instance if you assign it a 'New ExplorerForm' (or whatever name you gave it). However you can also just use a reference to your already open form (the Explorer variable in your code that is I think).

Just note that the method will only be called when the window is handling messages. Put simply, when it is responding to clicks, it will also execute methods send to it using Invoke().

I hope this answers your questions.

Willem
0
 
jeruteAuthor Commented:
As clear as mud. I am sorry  wmestrom but when it comes to delegates I am, in the official terminology, an idiot. I really don't understand them.

Which of these bits goes where?

Thanks for your patience

Jerute
0
 
wmestromCommented:
Hi Jerute,

I copied your code and if I understand it correctly you just have to change two things. I added a delegate definition and changed the call to the RefreshItems method. This should do the trick.

Willem
    '
    ' Main routines
    '
    Public Sub SendReceive()
        Try
            oApp = New Outlook.Application
            Dim oNS As Outlook._NameSpace = oApp.GetNamespace("mapi")
            Dim oSyncs As Outlook.SyncObjects
            Dim oSync As Outlook.SyncObject
            oNS.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).GetExplorer()
            oSyncs = oNS.SyncObjects
            oSync = oSyncs.Item("All Accounts")
            instance = oSync
            AddHandler instance.SyncEnd, AddressOf SyncEnd
            oSync.Start()
            oNS.Logoff()
            oSync = Nothing
            oSyncs = Nothing
            oNS = Nothing
            oApp = Nothing
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub
 
    'ADDED: Define a delegate
    Public Delegate Sub Refresh()
 
    Private Sub SyncEnd()
        RemoveHandler instance.SyncEnd, AddressOf SyncEnd
        oApp = Nothing
        Dim myProcesses As Process() = Process.GetProcessesByName("outlook")
        For Each myProcess As Process In myProcesses
            If myProcess.MainWindowTitle = "" Then myProcess.Kill()
        Next myProcess
        If Explorer.Visible = True Then
            'CHANGED: Use Invoke instead of a direct call
            Explorer.Invoke([Delegate].CreateDelegate(GetType(RefreshDelegate), Explorer, "RefreshItems"))
        End If
    End Sub
 
 
    '
    ' Explorer routines
    '
    Private Sub SendReceive(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tssendreceive.Click
        Main.SendReceive()
    End Sub
 
    Public Sub RefreshItems()
        Dim session As RDOSession = CreateObject("Redemption.RDOSession")
        session.Logon()
        folderitems = GetMailItemsFromFolder(session.GetFolderFromPath(currentfolder))
        UpdateItems(SelectRows(sortcolumn & " " & sortorder))
        session.Logoff()
    End Sub

Open in new window

0
 
jeruteAuthor Commented:
No, doesn't work. I have an issue with your code, and this may be the problem. I refer to the line

Explorer.Invoke([Delegate].CreateDelegate(GetType(RefreshDelegate), Explorer, "RefreshItems"))

My IntelliSense tells me that refreshdelegate is not defined. I assumed (maybe incorrectly) that this should be the same as the

Public Delegate Sub Refresh()

which, incidentally, I have had to change due to it being the same as form.refresh. Lets assume, for arguments sake, that I have put

Public Delegate Sub RefreshView().

One way or another I am still getting the exceptions thrown by this call...

A first chance exception of type 'System.Threading.ThreadStateException' occurred in System.Windows.Forms.dll
A first chance exception of type 'System.InvalidOperationException' occurred in wbcontrol.exe

I'm glad you are more patient than me. LOL. Thank you.
0
 
jeruteAuthor Commented:
I don't use sub main(), so where should this go?

my entry point is form_load...
0
 
jeruteAuthor Commented:
oh, and

thread.SetApartmentState(Threading.ApartmentState.STA)

isn't recognised by intellisense...

0
 
jeruteAuthor Commented:
but

thread.CurrentThread.SetApartmentState(Threading.ApartmentState.STA)

is. It didn't, however, solve the problem.

:(

I hate losing...
0
 
jeruteAuthor Commented:
Hi wmestrom

Although I still haven't found a solution to this problem I have assigned the points to you for your participation.

Thanks again.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.