【问题标题】:Initializing COM for Multiple COM Operations为多个 COM 操作初始化 COM
【发布时间】:2017-06-27 23:05:03
【问题描述】:

在线程中完成任何工作之前,每个线程初始化一次 COM,然后使用尽可能多的 COM 调用,是否正确的 COM 编码?

例如,在我的工作线程中,我设置了 Volume Shadow Copy Service 并使用 IFileOperation,在我的 GUI 线程中,我使用 CoCreateInstance(CLSID_ShellLink...) 在桌面上创建了快捷方式,并且使用CoCreateInstance( CLSID_TaskScheduler...) 创建任务计划程序作业。然后对于所有这些操作,我只需在启动程序和线程时每个线程调用一次HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);。最后当然是 CoUninitialize。

【问题讨论】:

  • 不是。你做了一个承诺,穿过你的心,希望死去。提供 COM 运行时无法自行判断的细节。你保证你会发送一个消息循环并且永远不会阻塞线程。你违背了这两个承诺。也许你会逃脱它,取决于。当您的程序死锁或未引发事件时,您知道您没有这样做。你永远不能 100% 确定它是安全的,你不知道在另一台依赖你信守承诺的机器上注入了哪些其他代码。无法调试,不仅仅是因为您不会靠近机器。
  • 你能用更简单的术语吗?我有点迷茫.. 作为一个 COM 初学者......你是指使用 COINIT_APARTMENTTHREADED 来处理消息循环吗?做事的最佳方式是什么?
  • 是的。获得消息循环并不难,您总是可以从 WPF 或 Winforms 项目模板中获得一个。如果您不想创建窗口,则不必创建。
  • 我应该改用 COINIT_MULTITHREADED 吗?我所有的 COM 库调用都在 gui 线程或工作线程中执行,但没有一个对象/调用在线程之间共享 - 我只是使用前面提到的对 VSS/IFileOperation/Task Scheduler/Shell Shortcuts 的调用。跨度>

标签: c++ com


【解决方案1】:

基础知识

CoInitialize(Ex) 需要为每个使用 COM 的线程调用。

如果这些是“您的”线程 - 即您控制它们的生命周期,则习惯上在线程函数的开头和结尾处进行 CoInitialize / Uninitialize。

这不是你的话题

如果线程是由其他人创建的,并且您不知道 COM 是否已初始化(例如,当您的 DLL 作为插件加载并通过“正常”导出函数调用时),那就有点棘手了。)

这里有两种方法:

(a) 尝试 CoInitialize(Ex),并标记返回码。

  • S_OK 表示你初始化了 com 库,你需要调用 CoUninitialize
  • S_FALSE 表示 COM 库已使用兼容的线程模型进行初始化,但您仍需要调用 CoUninitialize(以“反”)您的 CoInitialue
  • 错误代码(FAILED(hr) == true),这通常意味着COM linraries 已经初始化,但线程模型与您请求的模型不兼容。如果返回错误,请不要调用 CoUninitialize

(b) 创建您自己的主题
...并在那里完成所有 COM 工作(这可能不适用于所有插件 API)

OleInitialize 与 CoInitializeEx

某些 Windows API 可能需要 OleInitialize,即“CoInitialize plus more”。

没有很好的记录哪些服务需要 OleInitialize,但我遇到了一些 Shell API 的问题。 (即使主线程做了OleInitialize,工作线程仍然使用CoInitializeEx

【讨论】:

  • 谢谢彼得陈。当您说在线程函数的开头和结尾时-我正在使用Qt,因此我有一个工作对象位于工作线程中,我可以将执行需要在工作线程中执行的代码的事件传递给该对象-在我的案例我应该在创建工作线程和工作对象时初始化并在删除时取消初始化?或者我只是在使用 COM 的工作对象函数的开头和结尾初始化/uninit?那么每个线程在生命周期的开始和结束时执行一次,还是每个线程执行的函数执行一次?
  • 通常,每个线程一次,因为 init/deinit 有一些开销,并且让 COM 对象“存活” Uninitialize/Initialize 可能是未定义的行为。我对 QT 线程不够熟悉 - 最好为此打开一个单独的问题。
  • 我相信在调用 CoInitialize 而不必调用 OleInitialize 之前就足够了,但它似乎已经改变了,所以也需要明确地调用它。你也注意到了吗?
猜你喜欢
  • 1970-01-01
  • 2011-10-31
  • 2013-01-28
  • 1970-01-01
  • 2018-04-16
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
相关资源
最近更新 更多