FolderBrowserDialog and Apartment Model Misery

  • Thread starter Thread starter eBob.com
  • Start date Start date
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
Back
Top