无法从其他STA线程调用从STAThread创建的COM对象

Gan*_*ant 7 c# com multithreading interop marshalling

我是COM的新手,试图理解STA和MTA之间的区别.我试图创建一个示例,该示例将显示COM可以管理在STA中创建的对象的调用,该对象不是线程安全的.

MyCalcServer这里的类是使用ATL Simple Object创建的.使用的设置与本文中的相同:

  • 线程模型:公寓
  • 聚合:没有
  • 界面:自定义

MyCalcServer COM对象用于另一个C#项目,它是:

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();

    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这总是导致在InvalidCastExceptiont1的代码中引发(E_NOINTERFACE).我也尝试将ApartmentState更改为MTA但没有成功.

无法将"MyCOMLib.MyCalcServerClass"类型的COM对象强制转换为接口类型"MyCOMLib.IMyCalcServer".此操作失败,因为由于以下错误,对IID为"{B005DB8C-7B21-4898-9DEC-CBEBE175BB21}"的接口的COM组件的QueryInterface调用失败:不支持此类接口(HRESULT异常:0x80004002(E_NOINTERFACE)) .

有人可以解释我在这里做错了吗?

Dew*_*wfy 3

您明确要求 COM 为主线程创建实例,然后将其传递给另一个线程。当然在某些情况下是允许的(例如将 MyCalcServer 声明为多线程)。

但就您而言,您似乎需要为另一个线程创建代理。在常规 COM 客户端中,它是由 CoMarshalInterThreadInterfaceInStream 完成的。有一篇大文章来澄清它http://www.codeproject.com/KB/COM/cominterop.aspx

  • .Net 包装器自动在线程之间进行封送(否则终结器将无法工作)。如果自动编组器不起作用,错误将为 E_WRONG_THREAD (8001010E) (2认同)