从多线程公寓使用线程模型公寓访问 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正确的互操作封送处理应负责访问对象。
有没有人知道我可以尝试什么来做这项工作?
您不能使用 BackgroundWorker,它的线程类型错误。 无法更改,它使用线程池线程,并且始终是 MTA。 COM 会自动创建一个 STA 线程,为 COM 服务器提供一个热情好客的家,这将导致任何调用被封送。 它不适用于该组件,它没有正确注册其类型库。 无论如何,您都想避免的事情。
在启动它之前,您必须创建自己的 Thread 并调用其 SetApartmentState(( 方法将其切换到 STA。 在该线程上创建 COM 对象的实例也很重要,否则 CLR 仍将尝试封送调用。 从技术上讲,您需要抽取消息循环(Application.Run(,但您可能不需要这样做。 您会发现,如果调用死锁或预期事件未触发,则需要消息循环。
发生的事情是 COM Marshaller 无法封送对象。
第一个答案:标准编组需要一个类型库。可能是对象的类型库未正确注册,因此出现错误。您使用的是 x86 还是 x64?尝试使用 REGTLB 注册库。
第二个答案:如果这不起作用,简单的答案是使用 STA 公寓类型的线程。这可能意味着您无法使用后台工作者,但可能必须使用专门创建的线程,该线程在完成后销毁。如果我们谈论的是三分钟的操作,额外的开销可以忽略不计。
请注意,必须在要从中使用该对象的线程上创建对象,并且单元类型 msut 与对象的线程模型兼容,以避免封送。