C# – Cannot call COM object created from STAThread from oher STA threads

ccominteropmarshallingmultithreading

I am new to COM and trying to understand the difference between STA and MTA. I tried to create an example that would show that COM can manage calls to object created in STA that is not thread-safe.

MyCalcServer class here is created using ATL Simple Object. The settings used are the same as in this article:

  • Threading Model: Apartment
  • Aggregation: No
  • Interface: Custom

MyCalcServer COM object is used in another C# project which is:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        MyCOMLib.MyCalcServer instance = new MyCOMLib.MyCalcServer();
        string output1;
        instance.ChangeValue("Gant", out output1);
        Console.WriteLine(output1);


        Thread t1 = new Thread(() =>
        {
            while (true)
            {
                string output;
                instance.ChangeValue("Gant", out output);
                Console.WriteLine(output);
            }
        });
        t1.SetApartmentState(ApartmentState.STA);
        t1.Start();

        // :
        // also has t2 and t3 here with similar code
        // :

        t1.Join(); t2.Join(); t3.Join();

    }
}

However, this always results in InvalidCastException (E_NOINTERFACE) raised inside t1's code. I have also tried changing ApartmentState to MTA with no success.

Unable to cast COM object of type
'MyCOMLib.MyCalcServerClass' to
interface type
'MyCOMLib.IMyCalcServer'. This
operation failed because the
QueryInterface call on the COM
component for the interface with IID
'{B005DB8C-7B21-4898-9DEC-CBEBE175BB21}'
failed due to the following error: No
such interface supported (Exception
from HRESULT: 0x80004002
(E_NOINTERFACE)).

Could anybody please explain what I am doing wrong here?

Best Answer

You explicitly ask COM to create instance for main thread, then you pass this to another thread. Of course in some circumstance it is allowed (for example declare MyCalcServer as multithread).

But in your case it looks you need create proxy for another thread. In regular COM clients it is done by CoMarshalInterThreadInterfaceInStream. There is large article to clarify it http://www.codeproject.com/KB/COM/cominterop.aspx

Related Topic