Not using [STAThread]

  • Thread starter Thread starter Arne Vajhøj
  • Start date Start date
A

Arne Vajhøj

K said:
I see that VS by default pops in the
statement [STAThread] in the code and since
i started with all-blank-project this time, the part was missing.

Nevertheless, the program works and is happy. So i wonder - what's that
good for?

Is it something internal for VS or is it a
part of C#?

http://blogs.msdn.com/jfoscoding/archive/2005/04/07/406341.aspx
http://www.sellsbrothers.com/askthewonk/Secure/WhatdoestheSTAThreadattri.htm
http://www.codeguru.com/forum/showthread.php?t=407960
etc.

Arne
 
I see that VS by default pops in the
statement [STAThread] in the code and since
i started with all-blank-project this time,
the part was missing.

Nevertheless, the program works and is
happy. So i wonder - what's that good for?

Is it something internal for VS or is it a
part of C#?
 
I see that VS by default pops in the
statement [STAThread] in the code and since
i started with all-blank-project this time, the part was missing.

Nevertheless, the program works and is happy. So i wonder - what's that
good for?

Is it something internal for VS or is it a
part of C#?

It's related to .NET and how it uses COM. It signals to the compiler to
cause the thread executing that method (Main(), in the case of the VS
templates) to be initialize itself as a "single-threaded apartment" thread.

If the thread never actually uses COM, then you don't need it. You don't
describe any details about your project, so whether it's a bug to not
include that attribute (not statement) in your code, I can't say. For a
Forms-based Windows application though, it should be there. For a console
application, it's not necessarily needed.

Pete
 
Peter Duniho said:
I see that VS by default pops in the
statement [STAThread] in the code and since
i started with all-blank-project this time, the part was missing.

Nevertheless, the program works and is happy. So i wonder - what's that
good for?

Is it something internal for VS or is it a
part of C#?

It's related to .NET and how it uses COM. It signals to the compiler to
cause the thread executing that method (Main(), in the case of the VS
templates) to be initialize itself as a "single-threaded apartment"
thread.

If the thread never actually uses COM, then you don't need it. You don't
describe any details about your project, so whether it's a bug to not
include that attribute (not statement) in your code, I can't say. For a
Forms-based Windows application though, it should be there. For a console
application, it's not necessarily needed.


Thanks to both. Yes, i'm doing the console this time,
so it's probably the reason. Nevertheless, i'll put it in,
just for the sake of future sanity. :)
 
Thanks to both. Yes, i'm doing the console this time,
so it's probably the reason. Nevertheless, i'll put it in,
just for the sake of future sanity. :)

I wouldn't, if I were you. AFAIK, a normal console application never
actually has to initialize COM. By putting that attribute in, you cause
COM to be initialized. At a minimum, this is a waste. Additionally,
doing so in a console application could interfere with garbage collection
(I just found this doing a search on MSDN:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=16154&SiteID=1).

Basically, unless you have a specific need to explicitly specify the
apartment model, don't.

Pete
 
Peter Duniho said:
I wouldn't, if I were you. AFAIK, a normal console application never
actually has to initialize COM. By putting that attribute in, you cause
COM to be initialized.

Are you sure? I thought it just initialized the thread in a way which
allowed STA COM components to be used later. I've certainly used it in
the past with no ill effects.
At a minimum, this is a waste. Additionally,
doing so in a console application could interfere with garbage collection
(I just found this doing a search on MSDN:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=16154&SiteID=1).

It sounds like in that case there *was* COM involved though.
Basically, unless you have a specific need to explicitly specify the
apartment model, don't.

I guess the only worry is if you really don't know whether the
underlying .NET code is going to use COM at some point. I think this is
a significant problem - it's really not terribly obvious which APIs
beyond some (but not all?) WinForm controls use COM under the hood.
 
Thanks to both. Yes, i'm doing the console this time,
I wouldn't, if I were you. AFAIK, a normal console application never
actually has to initialize COM. By putting that attribute in, you cause
COM to be initialized. At a minimum, this is a waste. Additionally,
doing so in a console application could interfere with garbage collection
(I just found this doing a search on MSDN:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=16154&SiteID=1).
Basically, unless you have a specific need to explicitly specify the
apartment model, don't.


Great info. Thanks!
 
Are you sure? I thought it just initialized the thread in a way which
allowed STA COM components to be used later. I've certainly used it in
the past with no ill effects.

Am I sure? No...that's why I wrote "AFAIK" (i.e. "as far as I know").
However, normally the way you initialize a thread's apartment state is to
pass the appropriate flag, either COINIT_APARTMENTTHREADED or
COINIT_MULTITHREADED, when calling CoInitializeEx().

If the .NET is somehow using that attribute to turn it into a call to
CoInitializeEx() (and I would expect it to), then using the attribute
would thus imply an initialization of COM.
It sounds like in that case there *was* COM involved though.

Right. My reading of the post is that the leak happened because COM was
involved and being used inappropriately. The point here is that the OP is
suggesting that he'll put that attribute in now, "just in case", but in
fact if and when it actually becomes relevant, it could actually _hurt_ to
have a single-threaded apartment rather than help.

In other words, at the time that the attribute becomes relevant, the OP
had better be making a conscious decision about which apartment model to
use and given that, they will have every opportunity to add the correct
attribute at that time. Until that time, it isn't adding anything useful,
and could very well lead to loading COM into the process when it wasn't
necessary.

For what it's worth, I ran a quick test, modifying an existing console
application I had lying around by adding the [STAThread] attribute to the
Main() method. Comparing the loaded DLL's for the process between the two
instances, the one with the attribute had three extra DLLs: MSCTF.DLL,
UXTHEME.DLL, and PRLHOOK.DLL. The last one is particular to my Windows
installation (the description is "Parallels Helper Hook", so presumably it
got loaded as a side-effect of one of the other DLLs and because I'm
running Windows in a VM), but I'd guess the other two would show up on
anyone's computer.

I admit, even after some quick Googling, I don't have an explanation for
_why_ those particular DLLs get sucked in when STAThread is specified.
They don't seem directly related to COM per se. But I can confirm there's
a definite difference in how the process executes even if all you've done
is add that attribute.

So, again: I would not add it until such point in time if and when it is
actually needed. It's not going to help anything, and it could be
detrimental.

Pete
 
Peter Duniho said:
Am I sure? No...that's why I wrote "AFAIK" (i.e. "as far as I know").

Well, to be picky that was in the sentence saying that you didn't have
to initialize COM - the following sentence sounded more confident :)
However, normally the way you initialize a thread's apartment state is to
pass the appropriate flag, either COINIT_APARTMENTTHREADED or
COINIT_MULTITHREADED, when calling CoInitializeEx().

If the .NET is somehow using that attribute to turn it into a call to
CoInitializeEx() (and I would expect it to), then using the attribute
would thus imply an initialization of COM.

Interestingly, the docs for STAThreadAttribute say:

It sounds like in that case there *was* COM involved though.

Right. My reading of the post is that the leak happened because COM was
involved and being used inappropriately. The point here is that the OP is
suggesting that he'll put that attribute in now, "just in case", but in
fact if and when it actually becomes relevant, it could actually _hurt_ to
have a single-threaded apartment rather than help.

In other words, at the time that the attribute becomes relevant, the OP
had better be making a conscious decision about which apartment model to
use and given that, they will have every opportunity to add the correct
attribute at that time. Until that time, it isn't adding anything useful,
and could very well lead to loading COM into the process when it wasn't
necessary.

For what it's worth, I ran a quick test, modifying an existing console
application I had lying around by adding the [STAThread] attribute to the
Main() method. Comparing the loaded DLL's for the process between the two
instances, the one with the attribute had three extra DLLs: MSCTF.DLL,
UXTHEME.DLL, and PRLHOOK.DLL. The last one is particular to my Windows
installation (the description is "Parallels Helper Hook", so presumably it
got loaded as a side-effect of one of the other DLLs and because I'm
running Windows in a VM), but I'd guess the other two would show up on
anyone's computer.

I admit, even after some quick Googling, I don't have an explanation for
_why_ those particular DLLs get sucked in when STAThread is specified.
They don't seem directly related to COM per se. But I can confirm there's
a definite difference in how the process executes even if all you've done
is add that attribute.

So, again: I would not add it until such point in time if and when it is
actually needed. It's not going to help anything, and it could be
detrimental.

Pete
 
(Apologies if the first bit of this comes through twice.)

Peter Duniho said:
Am I sure? No...that's why I wrote "AFAIK" (i.e. "as far as I know").

Well, to be picky that was in the sentence saying that you didn't have
to initialize COM - the following sentence sounded more confident :)
However, normally the way you initialize a thread's apartment state is to
pass the appropriate flag, either COINIT_APARTMENTTHREADED or
COINIT_MULTITHREADED, when calling CoInitializeEx().

If the .NET is somehow using that attribute to turn it into a call to
CoInitializeEx() (and I would expect it to), then using the attribute
would thus imply an initialization of COM.

Interestingly, the docs for STAThreadAttribute say:

<quote>
The COM threading model can be set to single-threaded apartment or
multithreaded apartment. The application thread is only initialized for
COM interop if the thread actually makes a call to a COM component. If
COM interop is not used, then the thread is not initialized.
</quote>

(I hadn't seen that before this post, btw.)

I *hope* it's accurate, but you never know...
Right. My reading of the post is that the leak happened because COM was
involved and being used inappropriately. The point here is that the OP is
suggesting that he'll put that attribute in now, "just in case", but in
fact if and when it actually becomes relevant, it could actually _hurt_ to
have a single-threaded apartment rather than help.

Yes, that's true. Just to be clear though, I think we both agree that
it's not going to hurt garbage collection when COM *isn't* involved.
In other words, at the time that the attribute becomes relevant, the OP
had better be making a conscious decision about which apartment model to
use and given that, they will have every opportunity to add the correct
attribute at that time. Until that time, it isn't adding anything useful,
and could very well lead to loading COM into the process when it wasn't
necessary.

That's reasonable. There's still the issue of what happens when COM
unwittingly gets dragged in - but that will be an issue either way.

<snip dll stuff, purely because I don't have anything to say about it>
 
Interestingly, the docs for STAThreadAttribute say:

<quote>
The COM threading model can be set to single-threaded apartment or
multithreaded apartment. The application thread is only initialized for
COM interop if the thread actually makes a call to a COM component. If
COM interop is not used, then the thread is not initialized.
</quote>

(I hadn't seen that before this post, btw.)

I *hope* it's accurate, but you never know...

Sure, I'd hope it's accurate too. But I've seen too many inaccurate
statements in the docs to be confident that it is.

Especially since when I compared two different console applications, the
only difference between the two being the presence of the STAThread
attribute in one, and saw that the one with the STAThread attribute does
in fact load additional DLLs, I become somewhat more confident that I
can't trust MSDN on this one.

I don't have a good explanation for why the particular DLLs that got
loaded did in fact get loaded. But I know for sure that they did, and I
know for sure that it's a stable behavior (that is, add the attribute,
they show up, remove the attribute, they go away).

Even if the behavior was different on someone else's computer, it's clear
to me that that attribute is doing more, even when COM isn't explicitly
involved, than just setting some flag in the managed thread for the COM
interop to look at if it ever gets invoked.

Something is _executing_ differently, even when COM isn't used (or else it
turns out that there's no such thing as a .NET console application that
doesn't use COM...all I know is the console application was a trivial
"print this float" program, and for all I know .NET _is_ in fact using COM
for some reason, but if so that's even more reason to be concerned, since
it means COM gets used implicitly for the most trivial programs).
Yes, that's true. Just to be clear though, I think we both agree that
it's not going to hurt garbage collection when COM *isn't* involved.

Well, I do agree with that statement. The problem is, though, that I
can't qualify "involved" with "explicitly". My experiment shows me that
something different happens with that attribute. It _might_ be that COM
gets used implicitly, in which case there could still be a garbage
collection issue. Or it could just be that .NET is loading extra DLLs
without actually using COM past that point, in which case I think it's
likely that wouldn't cause the GC issue to show up.

But I don't have any practical way to know the difference. I mean, if I
really cared I suppose I could research this and track down the actual
answer. But I don't, especially since I think there's already other good
reasons to leave off the attribute unless it's actually needed. So I just
put that data in the "one more reason not to include the attribute"
column. :)

Pete
 
Jon Skeet said:
(Apologies if the first bit of this comes through twice.)



Well, to be picky that was in the sentence saying that you didn't have
to initialize COM - the following sentence sounded more confident :)


Interestingly, the docs for STAThreadAttribute say:

<quote>
The COM threading model can be set to single-threaded apartment or
multithreaded apartment. The application thread is only initialized for
COM interop if the thread actually makes a call to a COM component. If
COM interop is not used, then the thread is not initialized.
</quote>

(I hadn't seen that before this post, btw.)

I *hope* it's accurate, but you never know...


Well, it's not accurate a all.
Actually, when the (STA/MTA) attribute is set on Main, then COM gets
initialized *before* entering main, that is, ole32!CoInitializeEx is called
by the CLR before it enters managed code.
When the attribute is not set, and the thread is not initialized explicitly
, then the CLR will initialize the thread to join the MTA when calling into
COM for the first time.

To resume:
You have to set the STA/MTA attribute whenever you want to force your main
thread (your program's entry point) to run in a compatible apartment.
Calling into COM from a compatible apartment is the most effective way to
call into COM, as there is no need to marshal the calls across incompatible
apartments.
For Windows Forms, the compatible apartment is STA, the reason for this is
that WF needs an STA for drag/drop functionality and because a number of
controls are COM based and need an STA apartment to function properly

A console application doesn't need the attribute, unless it explicitly calls
into COM from it's main thread.
A console application that sets it's main thread to enter an STA, must pump
a message queue. This is not only a .NET requirement (finalizer thread),
it's a general COM requirement.
A console application that sets it's main thread to enter the MTA, does not
need a message pump.


Willy.
 
Jon Skeet said:
Thanks for clearing up the confusion. I was kinda hoping you'd step in
at some point as resident COM expert :)



The problem is that once you start to document "implementation details", you
also need to update the docs whenever *the* implementation changes. In this
particular case the docs were not updated after V1.1 changed the point where
COM was initialized. In general (and in this case), this is a non-issue,
such changes do not affect your code, but there may be others.....


Willy.
 

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

Back
Top