从多线程公寓使用线程模型公寓访问 COM dll 时出错

本文关键字:公寓 COM dll 访问 出错 线程 多线程 模型 | 更新日期: 2023-09-27 18:34:14

我必须与第三方应用程序通信,唯一的方法是访问提供的COM组件。由于交互大约需要 3 分钟,因此必须在后台进行。因此,我尝试做的是使用选项"嵌入式互操作类型"= true添加对组件的引用,并创建一个通过接口读取非常基本数据的测试。记录的执行此操作方法是使用以下代码:

System sys = new System();
if(Convert.ToBoolean(sys.Initialize()) && Convert.ToBoolean(sys.Login("John Smith", out userInstance)))
Project proj = new Project();
if (Convert.ToBoolean(proj.Open(sys, m_projName, m_scenarioName)))
    someValue = proj.Name;

这在使用后台工作者之前可以完美运行。然后我在第一行代码中收到以下错误:

无法将类型为"System.__ComObject"的 COM 对象强制转换为接口类型"ICAPILib.System"。 此操作失败,因为 COM 组件上的 COM 组件对具有 IID"{1F5EB3E2-35F6-11D2-A191-0060083A260B}"的接口的 QueryInterface 调用失败,原因是出现以下错误:加载类型库/DLL 时出错。(HRESULT的例外:0x80029C4A(TYPE_E_CANTLOADLIBRARY((。

我已经尝试重新注册组件,但没有任何成功。

当使用BackgroundWorker 时,Thread Apartment类型显然是MTA。COM 组件将线程模型设置为单元。如果我理解了这篇文章http://msdn.microsoft.com/en-us/library/eaw10et3.aspx正确的互操作封送处理应负责访问对象。

有没有人知道我可以尝试什么来做这项工作?

从多线程公寓使用线程模型公寓访问 COM dll 时出错

您不能使用 BackgroundWorker,它的线程类型错误。 无法更改,它使用线程池线程,并且始终是 MTA。 COM 会自动创建一个 STA 线程,为 COM 服务器提供一个热情好客的家,这将导致任何调用被封送。 它不适用于该组件,它没有正确注册其类型库。 无论如何,您都想避免的事情。

在启动它之前,您必须创建自己的 Thread 并调用其 SetApartmentState(( 方法将其切换到 STA。 在该线程上创建 COM 对象的实例也很重要,否则 CLR 仍将尝试封送调用。 从技术上讲,您需要抽取消息循环(Application.Run(,但您可能不需要这样做。 您会发现,如果调用死锁或预期事件未触发,则需要消息循环。

发生的事情是 COM Marshaller 无法封送对象。

第一个答案:标准编组需要一个类型库。可能是对象的类型库未正确注册,因此出现错误。您使用的是 x86 还是 x64?尝试使用 REGTLB 注册库。

第二个答案:如果这不起作用,简单的答案是使用 STA 公寓类型的线程。这可能意味着您无法使用后台工作者,但可能必须使用专门创建的线程,该线程在完成后销毁。如果我们谈论的是三分钟的操作,额外的开销可以忽略不计。

请注意,必须在要从中使用该对象的线程上创建对象,并且单元类型 msut 与对象的线程模型兼容,以避免封送。