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

我是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();
    
        }
    }
    

    但是,这总是会导致在t1代码中InvalidCastException (E_NOINTERFACE)。 我也尝试将ApartmentState更改为MTA,但没有成功。

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

    有谁能解释我在这里做错了吗?


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

    但在你的情况看起来你需要为另一个线程创建代理。 在常规的COM客户端中,它由CoMarshalInterThreadInterfaceInStream完成。 有大篇文章来澄清它http://www.codeproject.com/KB/COM/cominterop.aspx


    我设法得到了这个决心。

    由于我是COM新手,对Proxy / Stub了解不多,而且他们需要在STA和STA之间编组东西。 创建了一个新的ATL项目并确保我有“合并代理/存根”选项。 问题消失了。

    我发现这个页面的信息很有用:为什么我要将代理/存根代码与我的DLL项目合并。

    代理/存根为您的组件提供标准编组。 在许多情况下,基于DLL的组件可能不需要代理/存根,因为它在客户端的相同上下文中运行,而且这个选项起初似乎毫无用处。 但是,COM使用编组进程在多线程情况下同步对组件的访问。 因此,基于DLL的组件至少需要两种情况下需要代理/存根DLL:

  • 它运行多线程客户端,需要在公寓之间传递接口指针(STA到STA或MTA到STA)。

  • DCOM可以为基于DLL的组件提供代理过程,以便可以在分布式环境中访问它。 在这种情况下,代理/存根需要在机器之间进行编组。

  • 通过将代理/存根代码与您的实现进行合并,您不必分配两个DLL,即只有一个。

    我将Dewfy的回答标记为接受,因为他已经阐明了代理主题。

    链接地址: http://www.djcxy.com/p/44345.html

    上一篇: Cannot call COM object created from STAThread from oher STA threads

    下一篇: Ant: failed to create task or type runtarget