无法从其他 STA 线程调用从 STAThread 创建的 COM 对象
我是 COM 新手,试图了解 STA 和 MTA 之间的区别。我尝试创建一个示例来表明 COM 可以管理对 STA 中创建的非线程安全对象的调用。
这里的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();
}
}
但是,这总是会导致InvalidCastException
(E_NOINTERFACE) 在 t1 的代码中引发。我也尝试将 ApartmentState 更改为 MTA,但没有成功。
无法转换 COM 对象类型 'MyCOMLib.MyCalcServerClass' 到 接口类型 'MyCOMLib.IMyCalcServer'。这 操作失败,因为 COM 上的 QueryInterface 调用 IID 接口组件 '{B005DB8C-7B21-4898-9DEC-CBEBE175BB21}' 由于以下错误而失败:否 支持此类接口(异常 来自 HRESULT:0x80004002 (E_NOINTERFACE))。
有人可以解释一下我在这里做错了什么吗?
I am new to COM and trying to understand the difference between STA and MTA. I tried to create an example that would show that COM can manage calls to object created in STA that is not thread-safe.
MyCalcServer
class here is created using ATL Simple Object. The settings used are the same as in this article:
- Threading Model: Apartment
- Aggregation: No
- Interface: Custom
MyCalcServer
COM object is used in another C# project which is:
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();
}
}
However, this always results in InvalidCastException
(E_NOINTERFACE) raised inside t1's code. I have also tried changing ApartmentState to MTA with no success.
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)).
Could anybody please explain what I am doing wrong here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您明确要求 COM 为主线程创建实例,然后将其传递给另一个线程。当然在某些情况下是允许的(例如将 MyCalcServer 声明为多线程)。
但就您而言,您似乎需要为另一个线程创建代理。在常规 COM 客户端中,它是由 CoMarshalInterThreadInterfaceInStream 完成的。有一篇大文章来澄清它 http://www.codeproject.com/KB/COM /cominterop.aspx
You explicitly ask COM to create instance for main thread, then you pass this to another thread. Of course in some circumstance it is allowed (for example declare MyCalcServer as multithread).
But in your case it looks you need create proxy for another thread. In regular COM clients it is done by CoMarshalInterThreadInterfaceInStream. There is large article to clarify it http://www.codeproject.com/KB/COM/cominterop.aspx
我设法得到了这个决心。
由于我是 COM 新手,所以我对 Proxy/Stub 不太了解,也不知道它们是在 STA 和 STA 之间编组内容所必需的。创建新的 ATL 项目并确保选中“合并代理/存根”后。问题就消失了。
我发现此页面中的信息很有用: 为什么我要合并代理/存根使用我的 DLL 项目编写代码。
我会将 @Dewfy 的答案标记为接受,因为他对代理主题有了一些了解。
I managed to get this resolve.
As I'm new to COM, I don't know much about Proxy/Stub and that they're needed for marshaling stuffs between STA and STA. After created a new ATL project and make sure I have "Merge Proxy/Stub" ticked. The problem vanished.
I find the info from this page useful: Why would I want to merge Proxy/Stub code with my DLL project.
I will mark @Dewfy's answer as accept as he has shed some light on the Proxy topic.