I'm trying to understand C# thread apartments and have questions:
What exactly apartment is and what it contains?
The Apartment and the COM Threading Architecture
A process can have zero or more single-threaded apartments and zero or one multithreaded apartment.
Could anybody provide C# code-sample example or explanation for app, where are:
And when each case should\can be used?
A COM apartment is a logical concept. An apartment contains threads. An STA apartment can only contain one thread (hence the name "single threaded apartment"). An MTA can contain many threads (hence the name "multi threaded apartment"). Since an MTA can contain as many threads as it likes, there is at most one MTA in a process.
You can easily write these samples yourself. Just create threads in C#, and at the beginning of the thread entrypoint method, call Thread.SetApartmentState. Any threads you set to be MTA will live in the single MTA; any threads you set to STA will each live in their own STA.
Don't try to fiddle with a threadpool thread's apartment state. Those threads are shared (it's a pool), so it's not nice to be trying to change how they work. Also, once a thread belongs to an apartment, it cannot be changed.
Oh, I almost forgot to answer "when each case can / should be used": never, if you can help it.
Even when writing COM objects, I've always preferred to write "free-threaded" objects (that don't care what apartment they are in), but I can do that, because I have the superpower of understanding threads and knowing how to use a mutex. The threading model was created because (or at least in part because) many early semi-pro VB developers did not understand these concepts (maybe still don't?), and so COM people tried to come up with a system that would still let them easily do thready things.
So what happens when you try to pass a COM object from one apartment to another is that it has to go through special (annoying) magic to be marshaled; and even to make a call from one apartment to another has to go through special (annoying) magic. This is where all the jazz about proxies and stubs comes in. If you want to learn how all that stuff works, well... you know where the documentation is. But if you don't have to use it for some reason (like interop with existing COM objects), just avoid it if at all possible.
Additional questions from comments:
we can set apartment for thread, using Thread.SetApartmentState for a thread or [STA\MTAThread] attribute for method. But can we get\set apartment for objects?
No. A COM object belongs to the apartment it was created in, the end.
all calls to object which was created in STA apartment by its thread should be performed by this thread.
For objects that belong to the STA: Yes and no. "No" is because due to the special (annoying) magic that I referred to earlier (proxies and stubs), you can get a reference to a COM object belonging to STA#1 over on a different thread in STA#2, and make a call on it from there. "Yes" is because what happens under the hood is the proxy/stub magic sends a message from one thread to the other, and the method actually does always execute on the thread that the object belongs to. So you can /initiate/ a cross-apartment call from any thread... but the method itself will execute on the thread that the object belongs to. A problem that often comes up is that for one reason or another, the proxy/stub magic is not available for a given COM object... in which case you are stuck; you really can only use that object directly on the thread where it lives.
For MTA, it's a little looser--the special (annoying) marshaling stuff only comes into play when crossing apartment boundaries, not thread boundaries. So you have to be careful about handling synchronization yourself if you have multiple threads in your MTA.