Jon,
See inline ***
Willy.
Jon Skeet said:
That's not strictly true. It's required to run any application which
uses COM in a way which requires a single threaded apartment. For
instance, the ACT! CRM application has a COM library which only runs in
an STA thread. (Can you tell I know this from bitter experience?
****
Normally this should not be a problem, this is one of the beauty's of COM, it always works (maybe not very well, but ...) as long as
you follow the rules.
Note that a COM object flagged as threadingmodel = Apartment (as your ACT! CRM application), will always run in an STA, problems
arise when no default marshaler (OLEAUT) is used or a marshaler is not or not correctly registered. Another problem is that STA COM
objects are mostly tested and used from the same apartment of the creator in a single threaded application without inter apartment
marshaling requirements, whenever they are used in a multithreaded environment, they fail miserably.
Why do you think it's worth explicitly initializing it to MTA, given
that that's the default?
**** This is not (entirely) true, the default is unknown.
try this:
using System;
class Tester
{
public static void Main() {
Console.WriteLine(Thread.CurrentThread.ApartmentState);
}
And you will see the current state being "Unknown", that means that the thread running Main has not called CoInitializeEx (the same
applies to threads started from Main), now whenever you try to instantiate a COM object, COM (OLE32.dll) will check whether the
calling thread runs in a compatible apartment (STA or MTA or ...) which is never the case when CoInitializeEx has not been called.
In this case COM takes the appropriate action depending on the component apartment requirements (taken from the registry
threadingmodel - apartment, both, Free):
1 - if the object needs an STA, the COM library will check whether there exists a default STA for the process.
If there is no default STA, COM creates a new thread a hidden window and initiates a message pump. This apartment becomes the so
called default STA for the process. Note that in this case COM method calls need to be marshaled between the thread running Main and
the STA thread (running the object code).
2 - If the object needs an MTA, COM will simply initialize an MTA (if none already exists), and let the callers thread enter (run
inside) this MTA.
So in the above example, one may say whenever the thread running Main gets initialized it will be for MTA.
But if you count on this you are in for a surprise, to illustrate this just run this code:
using System;
class Tester
{
public static void Main() {
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
Console.WriteLine(Thread.CurrentThread.ApartmentState);
}
You see that the thread now runs in an STA, and calling your MTA COM objects methods will have to be marshaled.
This is not such a problem as long as you did initialize COM (like in the above example), but don't forget that a lot of the FCL
classes use COM interop under the covers, and they will initialize COM if the Apartment state is unknown, so you may end with your
Main running in an STA (I know this from bitter experience too ;-)).
+++++++++++++++