2010-02-01 81 views
7

我是COM新手,试图理解STA和MTA之间的区别。我试图创建一个示例,它将显示COM可以管理对STA中创建的非线程安全对象的调用。无法从其他STA线程调用STAThread创建的COM对象

MyCalcServer这里的类是使用ATL Simple Object创建的。使用的设置是一样this article

  • 线程模型:公寓
  • 聚合:没有
  • 接口:定制

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,但没有成功。

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)).

有没有人请解释我在做什么错在这里?

+0

也许JIT认为你没有使用“实例”并尽早发布它。 尝试在连接后放置Marshal.ReleaseComObject(实例)。 – adrianm 2010-02-01 08:50:19

+0

@adrianm仍然无法正常工作,但是这要感谢 – Gant 2010-02-01 08:57:32

+0

尝试将第一行更改为MyCOMLib.IMyCalcServer instance = new MyCOMLib.MyCalcServer(); 我认为只有接口(不是类)可以在线程之间编组。 – adrianm 2010-02-01 23:00:01

回答

3

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

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

+2

.NET包装会自动执行线程之间的封送处理(否则终结器将无法工作)。 如果自动编组不起作用,错误将是E_WRONG_THREAD(8001010E) – adrianm 2010-02-01 22:57:14

1

我设法得到这个决心。

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

我找到这个页面是有用的信息:Why would I want to merge Proxy/Stub code with my DLL project.

Proxy/stubs providing standard marshaling for your component. In many cases a DLL-based component may not need proxy/stub because it is running in the same context of its client, and this option may seem useless at first. However, COM uses the marshaling process to synchronize access to a component in multi-threaded situations. So, a DLL-based component will need a proxy/stub DLL in at least two cases:

  • It's running a multi-threaded client and needs to pass interface pointer between apartments (STA to STA or MTA to STA).

  • DCOM can provide a surrogate process for a DLL-based component so that it can be accessed in a distributed environment. In this case a proxy/stub is needed to marshal between machines.

By merging the proxy/stub code with your implementation, you don't have to distribute two DLLs, just the one.

我将迎来@ Dewfy的答案接受,因为他已经摆脱对代理话题的一些情况。

相关问题