none
Apartment of noncreatable COM object written in .NET RRS feed

  • Question

  • Hi,

    Let's say I have a COM interface called "IObserver" and another called "ISubject".  I also have a COM object derived from ISubject, which has a method called RegisterObserver, that takes as an argument an IObserver.  The COM object that implements ISubject is creatable (you can use CoCreateInstance to get one).  It is written in unmanaged code.

    Then in managed code I write, say a C# class, that implements IObserver.  I pass an instance of that class to the ISubject::RegisterObserver method.

    As far as I can tell this is the way one writes noncreatable COM objects in C#.

    The question is, what's the apartment of the IObserver implementation (the C# noncreatable COM object)?  How does the CCW determines the thread apartment?

    I made a project to test this, and it seems that no matter what I do, the apartment of the IObserver implementation is MTA.  Which is fine, because I like MTAs, but I can't find information about this anywhere that can confirm what I am finding.

    Thanks,

    Nick

    PS. I updated the post, previously I had asked the wrong question.  See my other post below for more information.
    • Edited by nr4christ Tuesday, November 27, 2012 3:35 PM
    Monday, November 26, 2012 9:09 PM

Answers

  • Hello nr4christ,

    1. >> When you say by default, do you mean there is a way to make them belong to an STA, or that they always belong to an MTA?

    1.1 I mean they seem to behave like MTA objects. But I think it is best to take a neutral stand on what apartment it will actually reside in. The next few points will illustrate this.

    2. >> Or does it depend on the client of the object (e.g., if an unmanaged client resides in an STA, then the .NET COM object also resides in the same STA)?

    2.1 It is more accurate to state the question as "does it depend on the client thread of the object which first created the object ?".

    2.2 Well, yes and no. A managed object exposed to COM does not seem to always reside in the apartment of the creating thread. The behavior is very unusual and unlike typical unmanaged COM objects.

    2.3 This despite the fact that the threading model of the managed object, after being registered to the registry, is marked as "Both".

    2.4 Being of "Both" apartment model indicates that the object will reside in the same apartment as that of the client thread which first creates the object. This is what "Both" means in COM.

    2.5 A managed object exposed as a COM object does seem to reside in the apartment of the client thread which first created it. However, when the object is marshaled to another thread of another apartment, it seem to adopt the apartment of that new thread.

    2.6 The object seem to run in the same thread as whatever thread it is being used in. This is very unusual in terms of apartment models.

    2.7 As an example, by the rules of COM, an STA object which has been marshaled to another STA apartment must be run in the apartment of the one in which it was first created.

    2.8 But I have seen cases in which a single managed object exposed as a COM object successfully run in two separate STA apartments without having the object perform its methods in the original creating STA apartment.

    3. My conclusion is : it is best to not try to determine the actual apartment of a managed object.

    3.1 As mentioned earlier, with .NET, Microsoft has decided to avoid the concepts of apartments and thread-affinity as much as possible and managed objects are accessible from any thread.

    3.2 And because it can be accessed from any thread, the object must use thread-synchronization tools like lock statements in order to maintain thread-safety.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    • Marked as answer by nr4christ Thursday, November 29, 2012 4:57 PM
    Thursday, November 29, 2012 7:10 AM

All replies

  • Hi Nick,

    Welcome to the MSDN Forum.

    I am trying to involve some other one into this case, wait it patiently, please.

    Thank you.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, November 27, 2012 10:27 AM
    Moderator
  • I just realized I had asked the wrong question in my original post, and I edited it to reflect the correct question.

    I know what's the apartment of the ISubject implementation, because it is a creatable COM object.  In this case it is MTA, but that's not what I wanted to ask.

    What's the apartment of the C# implementation of IObserver, the noncreatable object?  How is it determined?  How the CCW determines it?

    It doesn't seem to matter whether I allocate the IObserver implementation in a MTA or STA thread, or whether I pass the implementation to ISubject::RegisterObserver from MTA or STA thread.

    The way I am testing this is by calling two methods in ISubject concurrently, which results in two concurrent calls to IObserver.  If IObserver resided in a STA, then the calls would be serialized, but they are not.  IObserver seems to always reside on MTA no matter what I do.


    • Edited by nr4christ Tuesday, November 27, 2012 3:38 PM
    Tuesday, November 27, 2012 3:21 PM
  • Hello nr4christ,

    1. It is confirmed that managed objects which are exposed as COM objects are MTA-based by default.

    2. With .NET, Microsoft has decided to avoid the concepts of apartments and thread-affinity as much as possible.

    3. All objects are accessible from any thread and the onus is on the developer to ensure thread-safety by using lock statements.

    4. The MTAThreadAttribute and the STAThreadAttribute do not apply to managed classes. They apply to unmanaged COM objects which are used in managed code.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Wednesday, November 28, 2012 7:26 AM
  • Bio,

    Thanks a lot for your reply!

    You said that "managed objects which are exposed as COM objects are MTA-based by default".

    When you say by default, do you mean there is a way to make them belong to an STA, or that they always belong to an MTA?  Or does it depend on the client of the object (e.g., if an unmanaged client resides in an STA, then the .NET COM object also resides in the same STA)?

    Nick


    • Edited by nr4christ Wednesday, November 28, 2012 6:27 PM
    Wednesday, November 28, 2012 6:26 PM
  • Hello nr4christ,

    1. >> When you say by default, do you mean there is a way to make them belong to an STA, or that they always belong to an MTA?

    1.1 I mean they seem to behave like MTA objects. But I think it is best to take a neutral stand on what apartment it will actually reside in. The next few points will illustrate this.

    2. >> Or does it depend on the client of the object (e.g., if an unmanaged client resides in an STA, then the .NET COM object also resides in the same STA)?

    2.1 It is more accurate to state the question as "does it depend on the client thread of the object which first created the object ?".

    2.2 Well, yes and no. A managed object exposed to COM does not seem to always reside in the apartment of the creating thread. The behavior is very unusual and unlike typical unmanaged COM objects.

    2.3 This despite the fact that the threading model of the managed object, after being registered to the registry, is marked as "Both".

    2.4 Being of "Both" apartment model indicates that the object will reside in the same apartment as that of the client thread which first creates the object. This is what "Both" means in COM.

    2.5 A managed object exposed as a COM object does seem to reside in the apartment of the client thread which first created it. However, when the object is marshaled to another thread of another apartment, it seem to adopt the apartment of that new thread.

    2.6 The object seem to run in the same thread as whatever thread it is being used in. This is very unusual in terms of apartment models.

    2.7 As an example, by the rules of COM, an STA object which has been marshaled to another STA apartment must be run in the apartment of the one in which it was first created.

    2.8 But I have seen cases in which a single managed object exposed as a COM object successfully run in two separate STA apartments without having the object perform its methods in the original creating STA apartment.

    3. My conclusion is : it is best to not try to determine the actual apartment of a managed object.

    3.1 As mentioned earlier, with .NET, Microsoft has decided to avoid the concepts of apartments and thread-affinity as much as possible and managed objects are accessible from any thread.

    3.2 And because it can be accessed from any thread, the object must use thread-synchronization tools like lock statements in order to maintain thread-safety.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    • Marked as answer by nr4christ Thursday, November 29, 2012 4:57 PM
    Thursday, November 29, 2012 7:10 AM
  • Thanks a lot Bio.  That helps.  I think you are describing the behavior of what Adam Nathan described in his book as ".NET objects are always exposed to COM in a context-agile fashion, effectively as if they aggregate the free-threaded marshaller" (.NET and COM, The Complete Interoperability Guide, pg. 282).  But I didn't quite understand the whole implications, which I think you have explained better than Nathan.

    Thanks!

    Thursday, November 29, 2012 4:57 PM
  • Hello nr4christ,

    >> I think you are describing the behavior of what Adam Nathan described in his book...

    Yes, I was in fact referring to Adam Nathan's wonderful book. Glad to be of help :-)

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Thursday, November 29, 2012 5:56 PM