Search code examples
c#c++comatl

Object apartment vs Thread apartment


I read about apartment model, but it is still confusing me when I'm trying to understand the following: whose apartment dictates the apartment model? Is it the thread's apartment or the apartment of the created object?
Consider the following scenario:

  1. I've created C++ ATL COM dll that has only one interface which is ISimpleCom, and I have a class the implements that interface which has only one method test(); This class publicly inherit from CComObjectRootEx<CComSingleThreadModel> which sets STA apartment.

  2. Reference this DLL in C# WinForms project, and create the SimpleCom object on a MTA thread (not the UI thread). The question is: Lets say UI thread call test() on this object, will it be marshaled to the thread created the object or it will be executed on the UI thread ?

    • If it follows the object COM apartment this call should be marshaled to the thread who created the object because it is an STA object.
    • If it follows creating thread apartment which is MTA, it should be executed on the UI thread.

Which one is the correct one?


Solution

  • Simple rules:

    • A thread might be a member of zero or one apartments
    • Single threaded apartments (STA) consist of single thread, MTA - of one or more threads, but there can be at most one MTA per process
    • Threads "join" apartments at the time of their COM initialization

    So a piece of code is executed either in STA (on STA thread), or in MTA, or the thread is not yet initialized with COM. When you instantiate an object through COM, COM will match apartment model to the type of apartment the API is called from.

    This class publicly inherit from CComObjectRootEx which sets STA apartment.

    No. This has nothing to do with setting apartment model. CComSingleThreadModel says that this class is using simple base which is good for objects to be run on STA - in particular it will not use InterlockedXxx API or critical sections when it comes to accessing object's reference counter because the class is assumed to live within single thread. This does set apartment model of the COM class, it does not indicate that this class is to be run on STA, this just provides suitable base class.

    Apartment model for the ATL COM DLL hosted class will be indicated on .RGS file, associated with the COM class, and will be merged into registry with DLL registration. If this is "Apartment" model then...

    create the SimpleCom object on a MTA thread (not the UI thread).

    ... COM will see that it cannot instantiate on the calling thread directly, because the thread belongs to MTA. So COM will instantiate on the worker STA thread and will create a proxy/stub pair to marhshal the requested interface into caller MTA.