如何从库的角度处理COM(未)初始化?

4
阅读了本站上的几个答案,我了解到 CoInitialize(Ex)应该由线程的创建者调用。然后,运行在该线程中的任何代码都可以使用COM。如果该代码恰好通过自身调用CoInitialize(Ex),那么这将是无害的,因为它不会产生任何影响。它不应该调用CoUninitialize - 这也应该由线程的创建者完成 - 但如果它检查CoInitialize(Ex)的(保存的)结果,即S_FALSE,则它不会这样做。如果创建者不承担执行初始化的责任,则线程将处于该代码的“掌控”下,以选择适当的线程模型,从此以后将无法更改。 所有这些对编写和使用库有什么影响? 当所有代码都是您自己的,而且您有一个小团队时,很容易组织好COM(取消)初始化调用。但是,对于库,用户不应该需要知道它们如何执行操作,例如涉及COM。我讨厌在文档中写可以在代码中处理的内容。除非涉及VCL代码,否则不应做出关于库代码将在哪个线程中运行的任何假设。
我检查过的大多数开源库在初始化部分调用CoInitialize(Ex),并在终止部分调用CoUninitialize,甚至经常没有检查初始化是否成功。一些调用InitProc,但有些先检查IsLibrary
他们真正应该做什么?如果我自己编写一个单元,希望任何人都能够轻松使用,该怎么办?将所有涉及COM的内容包装在一个线程中,并使该线程执行其自己的COM(取消)初始化。
当使用那些开源单元在VCL应用程序中时,对于那些关于它的天真态度到底有多糟糕呢?它们的COM(un)初始化总是在主线程上运行,该线程已经由Forms.TApplication.Create执行。这是否使得单元中的调用无辜但无用?如果任何一个单元在.dpr中排在Forms之前,会怎么样?非VCL应用程序或DLL呢?我在纠正它们之前不应该使用这样的单元吗?我是否应该通过始终预先初始化COM来防范它们可能尝试做的事情?
这是一个相当复杂的问题,但归根结底就是:如何(使其易于)避免与COM(未)初始化相关的麻烦?

1
也许https://dev59.com/WYrda4cB1Zd3GeqPMW8f是调用Coinitialize和CoUninitialize的合适位置? - Jerry Dodge
你可以尝试阅读文档,特别是“备注”中的第一段,其中解释了重复(嵌套)调用。 - Ken White
我不熟悉Delphi,但一个重要的建议是,在调用CoInitialize(Ex)失败时不要调用CoUninitialize(请注意,S_FALSE表示成功)。如何使用CoInitialize(Ex)定义线程的公寓,因此另一个重要的建议是确保您的coclasses标记有适当的ThreadingModel,以便COM将处理线程封送,无论您的对象所在的公寓是什么。例如,如果不是,请不要将其标记为“both”。除此之外,文档是正确的。如果您想确保您的库处理所有情况,请使Com init成为一个选项(注册表等)。 - Simon Mourier
1
我认为在调用库中的任意函数时“初始化COM”只是个糟糕的主意。一个用作有效COM线程的线程必须要适当地发送消息或者进行其他与公寓类型相关的操作,而这些只有创建线程的人才知道。 - Chris Becke
1个回答

7

很简单。记录下你的库的任何使用者必须初始化COM。这是完全可接受和普遍做法。对于要求使用你的库的消费者来说,没有什么可担心的。如果他们未能按照要求执行,那就是他们的问题。正如你指出的那样,线程的创建者必须负责初始化COM,因此你没有其他可行的选择。


我强烈希望使它变得无懈可击。这意味着如果文档是处理COM的唯一选择,我不应该在我的库中使用COM,这非常有限制性。那么创建自己的线程并在其中运行代码呢?如果它不涉及任何GUI相关的内容(主要是MSXML),你有什么反对意见吗?此外,你只解决了作者的问题;你如何建议处理不遵循你原则的第三方代码?什么时候修补这些调用,什么时候放弃它们...? - Thijs van Dien
你无法让一个库变得百分之百安全。如果有人不遵守规则,它就无法正常工作。你应该努力让规则可以被遵守。 - David Heffernan
我旨在尽可能少地规定。 - Thijs van Dien
如果你愿意的话,就用自己的方式去做吧。由你决定。 - David Heffernan
从这个推断来看,我认为没有理由它不能工作,就像在另一个线程中使用COM没有什么大问题一样,只要它不是协作式的GUI操作,例如MSXML、WMI等等?我曾经见过某些情况下兔子洞非常深(需要消息泵,在不小心的情况下会死锁),但我想我的情况相当简单。 - Thijs van Dien
只是为了没有任何收益而增加了很多复杂性。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接