无法从其他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