[STAThread]

  • Thread starter Nicholas Paldino [.NET/C# MVP]
  • Start date
N

Nicholas Paldino [.NET/C# MVP]

Warren,

This is placed on the entry point of windows applications (and console I
think), to indicate that this thread is a single-apartment thread. This is
used for COM interop, which some of the controls (such as the rich text box)
require to provide their functionality. It doesn't hurt to have it there,
unless you are doing some COM interop which would interfere with this.

It doesn't hurt to have it there, and it is generally better to leave it
there, unless you are absolutely sure that there is no COM interop being
executed on that thread as well (which some of the classes in the framework
require as well).

Hope this helps.
 
W

warren

Hello,

Anyone can brief me what is this [STAThread] in front of the Main method
for?
and when must it be there, and when is it optional?

thank you.
 
G

Girish Bharadwaj

If you want to get a lowdown on STAThread, look in DCOM mailing archives and
other COM resources circa 1998.. You will find out all there is to know
about STAThreads and how they work and why its needed and how .NET framework
realized the need for this.

Oh, MSDN helps too.. :)

--
Girish Bharadwaj
Nicholas Paldino said:
Warren,

This is placed on the entry point of windows applications (and console I
think), to indicate that this thread is a single-apartment thread. This is
used for COM interop, which some of the controls (such as the rich text box)
require to provide their functionality. It doesn't hurt to have it there,
unless you are doing some COM interop which would interfere with this.

It doesn't hurt to have it there, and it is generally better to leave it
there, unless you are absolutely sure that there is no COM interop being
executed on that thread as well (which some of the classes in the framework
require as well).

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- nick(dot)paldino=at=exisconsulting<dot>com

warren said:
Hello,

Anyone can brief me what is this [STAThread] in front of the Main method
for?
and when must it be there, and when is it optional?

thank you.
 
W

Willy Denoyette [MVP]

STAThread is only required for Winforms applications.
This attribute initializes the main thread to run in a Single Threaded Apartment (STA), windows applications need this for:
- drag and drop support
- some windows controls (sure they are COM/ActiveX servers) have thread affinity, so should be created in an STA.

Other applications (console, services) normally don't have the same requirements, but it's better to explicitly initialize the main
thread for MTA.

Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
STAThread is only required for Winforms applications.

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? :)

Other applications (console, services) normally don't have the same requirements,
but it's better to explicitly initialize the main thread for MTA.

Why do you think it's worth explicitly initializing it to MTA, given
that that's the default?

I generally like to ignore the idea of COM threading models entirely if
I can avoid thinking about them.
 
W

Willy Denoyette [MVP]

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 ;-)).


+++++++++++++++
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
****
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.

In the case of using this library in .NET, if you don't specify
[STAThread] it fails to initialise at all - I can't remember the
exception offhand, but it definitely fails.
**** This is not (entirely) true, the default is unknown.

The default is that it's unknown until it needs to be chosen one way or
the other. At that point, if it hasn't been set explicitly, it acts as
if it had been set to MTA. From the docs for "Managed and Unmanaged
Threading":

<quote>
The following table lists the ApartmentState enumeration values and
shows the comparable COM apartment initialization call.

ApartmentState
enumeration value COM apartment initialization
MTA CoInitializeEx(NULL, COINIT_MULTITHREADED)
STA CoIntializeEx(NULL, COINIT_APARTMENTTHREADED)
Unknown CoInitializeEx(NULL, COINIT_MULTITHREADED)

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):

<snip>

The above disagrees with you - I'd be interested to know which is
definitely right, although if you're right then I don't know why my
code fails to initialise the COM object without STAThread applied.
 
W

Willy Denoyette [MVP]

Jon,

See inline ****.

Willy.

Jon Skeet said:
The default is that it's unknown until it needs to be chosen one way or
the other. At that point, if it hasn't been set explicitly, it acts as
if it had been set to MTA. From the docs for "Managed and Unmanaged
Threading":

**** It hasn't been set at all because the COM library didn't get initialized yet (se below).

<quote>
The following table lists the ApartmentState enumeration values and
shows the comparable COM apartment initialization call.

ApartmentState
enumeration value COM apartment initialization
MTA CoInitializeEx(NULL, COINIT_MULTITHREADED)
STA CoIntializeEx(NULL, COINIT_APARTMENTTHREADED)
Unknown CoInitializeEx(NULL, COINIT_MULTITHREADED)



<snip>

The above disagrees with you - I'd be interested to know which is
definitely right, although if you're right then I don't know why my
code fails to initialise the COM object without STAThread applied.

****
The above is wrong, just like Adam Nathan is wrong in his book ".Net and COM" (great book btw.) at page 208, I guess both the docs
and the book are based on pre v1.0 bits (note that in v2.0 things could change again ;-)).

If the STA/MTAThread attribute is not set, the CLR doesn't initialize the thread for COM (so no CoInitializeEx is called when
starting the thread running Main).
Now when you create an instance of an STA COM object on this thread, the object will be run on a COM managed STA thread the main
thread will enter the process MTA and a proxy will be returned to handle the marshaling between those incompatible apartments.

Like I showed you in the second sample, there is another way to enter an STA apartment. The difference between both is that the
STAThread attribute and setting the apartment state to STA, is that the former calls OleInitialize, effective initializing OLE
support (drag and drop clipboard access and in-place activation) and the latter only calls CoInitializeEx, effectively initializing
the COM library for this thread.

As far as your code failing, I have no clue (as there are several possible causes ) unless you can try to repro the case and supply
an HRESULT. Note that it's important to remember that the caller accesses the object through a proxy from an MTA thread, and MTA
threads (generaly) don't pump messages ......


Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
See inline ****.

<snip>

Okay. I'm still not sure I've "got it" but I'm not sure I'm *going* to
get it either - at least not until I really need to look into the
situation. Shame the docs are broken though (assuming you're right).

Thanks for the detail though - no doubt I'll need to google for this
thread some day :)
 
W

Willy Denoyette [MVP]

Hi Richard,

See inline ***


Willy.

Richard Grimes said:
If you do not specify an apartment type then just before COM is used the
first time on the thread, the thread will join the MTA. If you don't use COM
on the thread, then the thread will not be a member of an apartment, hence
'unknown'. Of course, the apartment membership is only important if the
apartment is needed and the only time when this is the case is when COM is
used. So to all intents and purpose the default apartment type is MTA.

*** I agree, when calling into COM when the apartment type is not yet explicitely set (no STA/MTAThread attribute or in code), the
runtime will call CoInitializeEx() and join the MTA. But this (IMO) doesn't mean MTA is the default for the thread running Main, to
me it's unknown ('NoApartment 'would be better IMO)) until someone joins an apartment by setting the Attribute or in code (note that
calling the FCL can initialize the threads apartment if not yet done I've been bitten by this several times).


His book is excellent - the *only* book you need to buy about COM and .NET.
However, p208 in my copy is a section called Events where he gives a basic
explanation of events (no COM details). Can you post the section where you
think he is wrong?

Sorry for the typo, it should read "page 280" the offending code is at the bottom.
 
R

Richard Grimes [MVP]

Willy said:
*** I agree, when calling into COM when the apartment type is not yet
explicitely set (no STA/MTAThread attribute or in code), the runtime
will call CoInitializeEx() and join the MTA. But this (IMO) doesn't
mean MTA is the default for the thread running Main, to me it's
unknown

Why? If there is no apartment, there's no apartment type, so even talking
about apartments is irrelevant said:
('NoApartment 'would be better IMO)) until someone joins an

agreed, because there isn't one!
apartment by setting the Attribute or in code (note that calling the
FCL can initialize the threads apartment if not yet done I've been
bitten by this several times).

right, and if that code does not specify an apartment type the thread will
automatically join the MTA!

I think we have to agree to disagree.
Sorry for the typo, it should read "page 280" the offending code is
at the bottom.

Yes, I see what you mean.

Richard
 
W

Willy Denoyette [MVP]

Richard Grimes said:
Willy Denoyette [MVP] wrote:
right, and if that code does not specify an apartment type the thread will
automatically join the MTA!
Agreed, if the code doesn't specify an apartment type,but that's not my
point, sorry if I wasn't clear.
The point is that you as a class user, don't know (some will say you
shouldn't know as it's an implementation detail) if/how the thread's
apartment will be initialized explicitely, take a look at the Management and
the DirectoryServices namespace classes, they spawn another thread and
initialize the apartment type explicitely for MTA because they (rightfully)
prefer MTA for components marked 'both', but MSFT could have taken STA as
well. I for one could opt to initialize for STA if a COM component I'm
instantiating is marked 'single threaded apartment' in my library classes.
You know that many classes in the FCL use existing COM components, this is
and as such the apartment requirements/implications are not documented, the
result is that many get bitten by this.
I think we have to agree to disagree.
Do we?
 

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