Jon Skeet said:
Out of interest, what are the problems one might find without this? For
test purposes I've often created forms which do very little, and rarely
bothered to put the STAThread attribute on them. They've been fine -
but I quite understand that either this was through chance or because I
wasn't using particular components.
Jon,
A couple of the Windows Forms controls are simple wrappers around ActiveX
COM controls, notably all the "Dialog Controls" are AX control wrappers, one
of them being the OpenFileDialog as used by the OP.
Such controls need a *pumping* STA thread to run on.
Now, if you don't initialize your UI thread to enter an STA, the CLR will
initialize the thread to enter the MTA whenever you call into COM for the
first time, that is when you create an instance of say OpenFileDialog. Note
that the v2 SP1 CLR initializes the thread to enter the MTA (if not marked
otherwise) even before it starts the main thread.
FileDialog (the wrapped AX dialog) as all other dialogs, is marked as
requiring an STA, so it can't get instantiated on the calling MTA thread,
COM takes care of this by creating a new thread that gets initialized to
enter an STA and creates the instance of the dialog on this thread and
returns a proxy to the caller.
That mean you'll end with the following (important for this discussion)
threads in a Forms application that doesn't mark it's main UI thread as
STAThread.
Main thread (UI) MTA.
GDI Thread MTA (used by Forms)
STA thread created by COM hosting the FileDialog AX control.
So far so good, the control runs on a compatible thread, and the caller
receives a proxy (a marshaled Interface Pointer). The problem however is
that the STA thread created by COM on your behalf isn't pumping messages,
that means that your OpenFileDialog cannot communicate with the callers
thread. The result is that the dialog cannot be used,it will not even
show-up (I guess) and the UI thread deadlocks.
Note also that the Finalizer (MTA) thread cannot access the controls STA
thread whenever he needs to run the Control's Finalize method. This is no
big deal in this scenario, as the control is non-functional anyway, but it's
a big issue when you have to deal with non-visual AX controls.
Willy.