C# 无法从其他STA线程调用从STAThread创建的COM对象
我是COM的新手,试图理解STA和MTA之间的区别。我试图创建一个示例,说明COM可以管理对在STA中创建的对象的调用,该对象不是线程安全的C# 无法从其他STA线程调用从STAThread创建的COM对象,c#,multithreading,com,interop,marshalling,C#,Multithreading,Com,Interop,Marshalling,我是COM的新手,试图理解STA和MTA之间的区别。我试图创建一个示例,说明COM可以管理对在STA中创建的对象的调用,该对象不是线程安全的 MyCalcServer这里的类是使用ATL简单对象创建的。使用的设置与中的相同: 线程模型:单元 聚合:否 界面:自定义 MyCalcServerCOM对象用于另一个C#项目,即: class Program { [STAThread] static void Main(string[] args) { MyC
MyCalcServer
这里的类是使用ATL简单对象创建的。使用的设置与中的相同:
- 线程模型:单元
- 聚合:否
- 界面:自定义
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的代码中出现无效的CastException
(E_NOINTERFACE)。我也尝试过将ApartmentState更改为MTA,但没有成功
无法强制转换类型为的COM对象
“mycmlib.MyCalcServerClass”到
接口类型
“mycmlib.IMyCalcServer”。这
操作失败,因为
COM上的QueryInterface调用
与IID接口的组件
“{B005DB8C-7B21-4898-9DEC-CBEBE175BB21}”
由于以下错误而失败:否
支持此类接口(例外情况)
来自HRESULT:0x80004002
(E_NOINTERFACE))
谁能解释一下我在这里做错了什么吗?您明确要求COM为主线程创建实例,然后将其传递给另一个线程。当然,在某些情况下是允许的(例如,将MyCalcServer声明为多线程)
但在您的情况下,似乎需要为另一个线程创建代理。在常规COM客户端中,它由CoMarshalInterThreadInterfaceInStream完成。有一篇大文章澄清了这一点我设法解决了这个问题 由于我是COM新手,我对代理/存根了解不多,而且它们是在STA和STA之间封送数据所必需的。创建一个新的ATL项目后,确保勾选了“合并代理/存根”。问题消失了 我发现此页面中的信息非常有用: 提供标准的代理/存根 组件的封送处理。在许多方面 在某些情况下,基于DLL的组件可能无法 需要代理/存根,因为它正在运行 在其客户的相同上下文中,以及 这个选项一开始可能看起来没用。 但是,COM使用封送处理 同步对数据库的访问的进程 多线程系统中的组件 情况。因此,一个基于DLL的组件 至少需要一个代理/存根DLL 两个案例:
- 它正在运行一个多线程客户端,需要传递接口 公寓之间的指针(STA到STA) 或MTA至STA)
- DCOM可以为基于DLL的组件提供代理进程,因此 它可以在一个 分布式环境。在这种情况下 需要一个代理/存根来封送 在机器之间
我将@Dewfy的回答标记为接受,因为他已经阐明了代理主题。也许JIT认为您没有使用“实例”,并提前发布了它。尝试在连接之后放置Marshal.ReleaseComObject(实例)。@adrianm仍然不工作,但感谢您尝试将第一行更改为mycmlib.IMyCalcServer instance=new mycmlib.MyCalcServer();我认为线程之间只能封送接口(而不是类)。@adiranm仍然得到相同的异常。幸运的是我解决了这个问题。无论如何谢谢:)+1的问题,我只是击中了同样的东西。我知道这是由于对一个公寓对象的跨线程调用,但我不明白为什么异常会抱怨抛出该对象。现在我知道了-它必须在强制转换期间查找编组支持,但没有找到,因此给出了一个一般性错误。可能更有帮助…Net包装器会自动在线程之间进行封送处理(否则终结器将无法工作)。如果自动封送处理不起作用,则错误将是E\u错误线程(8001010E)