FolderBrowserDialog and Apartment Model Misery

E

eBob.com

I have a multi-threaded app consisting of the UI thread and a number of
worker-bee threads. An enhancement which I'd like to make requires that the
worker-bee threads use FolderBrowserDialog. But the FolderBrowserDialog
form which appears has no "tree" for selecting the folder. My hours and
hours and hours of research indicate that this is a well known problem which
relates to the Apartment Mode/Mood/View/Model/Feng Shui/Whatever and the
allegation that the FolderBrowserDialog uses ActiveX. I've been able to
determine that if I tell my app not to create worker-bee threads but to do
all of the work on the UI thread the FolderBrowserDialog displays correctly.

I'm bleary eyed from all of the reading I've been doing but I think I recall
someone reporting that setting the Apartment Model for the worker-bee
threads can fix my problem. But I haven't come across any documented way of
doing that which works (see below). One of my problems maybe is that I
don't explicitly create the worker-bee threads. They seem to come about
because of the BeginInvoke method of a Delegate.

My first attemp to set the Apartment Model for the worker-bee threads was
this ...

Thread.CurrentThread.ApartmentState = ApartmentState.STA

.... but IntelliSense claims that something about this has been denigrated.

So than I tried ...

Thread.CurrentThread.SetApartmentState(ApartmentState.STA)

.... but that throws an InvalidOperationException.

I think I also read that there is a Project Property setting which allows
you to specify the Apartment Model of any created threads but I am unable to
find it in VBE 2008.

If I do manage to get the worker-bee threads running in Apartment Model STA
will I than have problems with the Excel COM interface which I use to create
a spreadsheet? (Some of the posts I've found say that this Apartment Model
stuff relates to COM.)

I hope someone can help me with this because I haven't experienced so much
misery with VB.Net in a long time.

Thanks, Bob
 
A

Armin Zingler

eBob.com said:
So than I tried ...

Thread.CurrentThread.SetApartmentState(ApartmentState.STA)

... but that throws an InvalidOperationException.

Call SetApartmentState _before_ starting the thread. See very first line in
the help on the SetApartmentState method.
IIRC, STA is the recommended state for Office Interop purposes.

see also:
http://msdn.microsoft.com/en-us/library/8sesy69e.aspx

Be aware that the Express edition does not have a Threads window, so it's
almost impossible to debug multithreaded applications reliably!



Armin
 
M

Michel Posseth [MCP]

Well i use a lot of multithreading if you just use the general rule that all
GUI interaction should be done on the Main ( GUI ) Thread
then you wil not encounter problems so first synchronize the calls to the
dialog with the GUI and then show the dialog should solve your problems .

I can not make out what your code is that starts the dialog but let me
show you a quick and dirty example of what i mean

Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click


Dim AsyncA As New methodInvokerA(AddressOf Me.SubRunningInSeperateThreadA)

AsyncA.BeginInvoke(Nothing, Nothing)

Dim AsyncB As New methodInvokerA(AddressOf Me.SubRunningInSeperateThreadB)

AsyncB.BeginInvoke(Nothing, Nothing)

Debug.WriteLine("hello it is me the main thread reporting that i fired both
threads")

Debug.WriteLine("and prooving that we run asynchronous")

End Sub

Delegate Sub methodInvokerA()

Delegate Sub methodInvokerB(ByVal Par As String)

Private Event eTShowDialog(ByVal threadname As String)

Private Sub SubRunningInSeperateThreadA()

' do some working stuff

For x As Integer = 0 To 1000

Debug.WriteLine("hello it is me worker thread A working really hard :)")

System.Threading.Thread.Sleep(10)

Next

RaiseEvent eTShowDialog("A")

End Sub

Private Sub SubRunningInSeperateThreadB()

' do some working stuff

For x As Integer = 0 To 500

Debug.WriteLine("hello it is me worker thread B working really hard :)")

System.Threading.Thread.Sleep(20)

Next

RaiseEvent eTShowDialog("B")

End Sub

Private Sub Form1_eTShowDialog(ByVal threadname As String) Handles
Me.eTShowDialog

If Me.InvokeRequired Then

'we are running in a nother thread as the GUI thread

'So lets synchronize the call to the GUI thread

Dim d As New methodInvokerB(AddressOf Form1_eTShowDialog)

Me.Invoke(d, New Object() {threadname})

Else

'we are running in the same thread as the GUI thread

Debug.WriteLine("hello about to fire the dialog on main GUI thread started
by thread " & threadname)

Using FbDlg As New FolderBrowserDialog

FbDlg.RootFolder = Environment.SpecialFolder.Desktop

FbDlg.Description = "thread " & threadname & " started this dialog"

FbDlg.ShowDialog(Me)

End Using

End If

End Sub

End Class





Maybe the above quick and dirty but working example will give you some ideas



HTH



Michel Posseth
 
M

Michel Posseth [MCP]

Armin

he can`t do that as he stated that the threads were invoked through
delegates , so i guess the thread he was playing with was his main thread


regards

Michel
 
A

Armin Zingler

Michel said:
Armin

he can`t do that as he stated that the threads were invoked through
delegates , so i guess the thread he was playing with was his main
thread

I don't know what that means. Somewhere he must create a new thread and
start it even if the function doing this was called by Invoke/Begininvoke.
He was mentioning "worker-bee" threads, so I think it was not all done in
the main thread.

Sorry, I didn't understand what the following part means and forgot to
re-read it again.

Armin
 
E

eBob.com

The Apartment State (Model) doesn't seem to be inherited by the sub-thread.
The UI/Form1 thread starts out as STA and is still STA just before the
sub-threads are created but the created sub-threads are MTA. Why? I have no
idea but that's what I see.

I think I've seen before that the Express edition doesn't have a Threads
window, but I've got to use Threads and I doubt that I can afford a
non-Express edition. I have structured the app so that it can be told not
to use threads. Hopefully that will allow me to debug any problem.
Hopefully!

Thanks, Bob
 
E

eBob.com

Thank you Michel. I wrote my app so that the sub-threads would go back to
the Form1/UI thread to update Form1 controls. I think I followed examples
found on the web and the code seemed to work. But now that I've moved to
VBE and the latest framework I get a message saying that I am doing it wrong
and I have to use

Control.CheckForIllegalCrossThreadCalls = False

until I have time to straighten out the Form1 updates.

In this case involving FolderBrowserDialog, of course, I am not updating any
Form1 controls, and I was hoping to avoid the verbose code (sorry, but
that's how it strikes me) to run the FolderBrowserDialog on the UI thread.
I got the impression that my problem is not running a Dialog on a non-UI
thread but running the FolderBrowserDialog on a non-STA thread. Would the
OpenFileDialog have caused me the same problems? I'm guessing not but I
really don't know.

Thanks again for the sample code. I haven't yet but I will be studying it
and taking advantage of it.

Bob
 
E

eBob.com

Armin Zingler said:
I don't know what that means. Somewhere he must create a new thread and
start it even if the function doing this was called by Invoke/Begininvoke.
He was mentioning "worker-bee" threads, so I think it was not all done in
the main thread.

Sorry, I didn't understand what the following part means and forgot to
re-read it again.


Armin

Well, that was't well written and re-reading it again probably would't have
helped. The thought process, or lack thereof, went as follows. ...

I had forgotten how I was creating the sub-threads (aka worker-bee threads).
And I think I read somewhere that when you set the Apartment Model for a
thread you have to do it real early in the thread's life, before it does
something - although I don't recall now what that something is. And in my
mind, or lack thereof, I was thinking OK, I will create the thread, then set
it's Apartment Model, and then tell it to start executing. But then I found
that I was using the BeginInvoke method of a Delegate and thus, so far as I
know, there's no opportunity to set the Apartment Model of the created
thread before it starts executing.

On this topic, I would rather be using "create thread" and "start running
the thread" APIs (that model is more familiar to me), but in .Net I have not
been able to find such APIs.

Thanks, Bob
 
E

eBob.com

eBob.com said:
Well, that was't well written and re-reading it again probably would't
have helped. The thought process, or lack thereof, went as follows. ...

I had forgotten how I was creating the sub-threads (aka worker-bee
threads). And I think I read somewhere that when you set the Apartment
Model for a thread you have to do it real early in the thread's life,
before it does something - although I don't recall now what that something
is. And in my mind, or lack thereof, I was thinking OK, I will create the
thread, then set it's Apartment Model, and then tell it to start
executing. But then I found that I was using the BeginInvoke method of a
Delegate and thus, so far as I know, there's no opportunity to set the
Apartment Model of the created thread before it starts executing.

On this topic, I would rather be using "create thread" and "start running
the thread" APIs (that model is more familiar to me), but in .Net I have
not been able to find such APIs.

Thanks, Bob
Well I've now discovered the Thread Class and after some more study expect
that I will switch to it. It seems more natural to me.

Thanks, Bob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top