发生了'System.Runtime.InteropServices.COMException'类型的异常。接口未注册(HRESULT异常:0x80040155)

时间:2011-11-22 05:47:06

标签: multithreading com

我正在尝试使用来自不同线程的COM对象,我收到此错误。单线程模型中不会发生相同的错误。

可能的原因是什么?

我尝试使用CComMultiThreadModel实现接口。仍然没有运气。

1 个答案:

答案 0 :(得分:0)

您尚未为COM对象注册代理/存根对象,因此无法将其接口编组到相关线程。

你有两个选择 a)注册代理。如果接口是您的应用程序的私有接口,则可以合并代理存根。如果不是,则应创建单独的DLL。 ATL向导可以帮助您生成代理,因此您可能已经拥有它们,而您只是没有安装/注册它们。

Proxies将确保对您的对象的调用发生在它注册的同一个COM公寓中。在你的情况下,STA。这也减少了锁定的需要 - 因为一次只能在您的代码中进行一次调用。 http://msdn.microsoft.com/en-us/library/ms809971.aspx

当然,您仍然需要防止重入,因为您的STA对象可能会在其外部呼叫期间重新进入。 http://blogs.msdn.com/b/cbrumme/archive/2004/02/02/66219.aspx

使用代理的缺点是在编组和等待STA时都存在性能成本。

在经典的Win32模型中,您应该始终将STA用于封装UI的COM对象,因为HWND始终绑定到单个线程。

b)聚合Free-threaded marshaller。 您还可以在ATL中找到此选项。自由线程编组器使您可以从进程中的任何公寓直接调用COM对象。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms694500(v=vs.85).aspx

当您使用FTM时,对您的对象的调用是直接的vtable调用 - 不涉及marshalliong。

选择此选项需要您使代码线程安全(通过应用适当的锁定),因为调用现在可以同时从多个线程进入。

额外的负担是FTM对象不能直接保存到接口指针,除非它确实知道这些对象也聚合了FTM。因此,当您从其他人那里获得IUnknown时,您需要将其存储在公寓中性格式中(例如在全局接口表中)。

出于这个原因和其他原因,FTM是了解他们正在做什么的人的高级选择。但它也是非UI代码的最高性能选项。

马丁