gpt4 book ai didi

c++ - 如何在 C++ 中维护对 COM 对象的弱引用?

转载 作者:IT老高 更新时间:2023-10-28 23:01:59 26 4
gpt4 key购买 nike

在我的应用程序中,我连接了各种用于创建 COM 对象的函数(例如 CoCreateInstanceEx ),以便在创建某个对象时得到通知。我正在跟踪 std::list 中所有创建的对象我正在遍历该列表以执行各种操作(例如检查哪些 OLE 对象已被激活)。

问题在于,现在,无论何时添加 IUnknown指向我的列表的指针,我调用 IUnknown::AddRef以确保它在我跟踪它时不会被破坏。但这不是我真正想要的。对象的生命周期应该与没有我的跟踪代码一样长(或短),所以我宁愿维护一个 weak reference在物体上。每当对某个跟踪的 COM 对象的最后引用被删除(因此该对象被破坏)时,我想得到通知以便我可以更新我的簿记(例如,通过将列表中的指针设置为 NULL).*

最好的方法是什么?现在,我正在修补所有已创建对象的(第一个)VTable,以便调用 IUnknown::Release通过第一个 vtable 得到通知。但是,这不适用于从多个接口(interface)(因此具有多个 vtable)继承的 COM 接口(interface),但我不确定这是否真的是一个问题:鉴于 Rules for Implementing QueryInterface , IUnknown::QueryInterface 应该总是只返回一个 IUnknown , 正确的?所以我可以这样做,然后修补那个 vtable。

此外,这种方法也有点麻烦,因为它涉及创建生成一些代码的 thunk。到目前为止,我只为 32 位实现了这个。不是什么大问题,但仍然存在。

我真的想知道是否没有更优雅的方法来对 COM 对象进行弱引用。有人知道吗?

*:接下来我要解决的问题是在我有事件的迭代器(我正在使用自定义迭代器对象)遍历 COM 对象列表的情况下使其正常工作。我可能需要跟踪事件的迭代器,一旦最后一个迭代器完成,从列表中删除所有空指针。或者类似的东西。

最佳答案

这不是一个答案,而是一系列问题,为什么这是一件非常棘手的事情 - 我将其作为答案,因为这里的信息太多而不适合评论:)

我的理解是,弱引用的概念在 COM 中是不存在的。您已经通过 IUnknown 获得了引用计数,这就是 COM 如何处理对象生命周期管理的总和。严格来说,除此之外的任何东西都不是 COM。

(.Net 确实支持这个概念,但它有一个实际的基于 GC 的内存管理器来提供适当的支持,并且可以将 WeakRef 对象与内存中的常规引用区别对待。但是对于 COM 非常简单的世界,情况并非如此假设,这是一个纯内存和指针的世界,仅此而已。)

COM 指定引用计数是每个接口(interface)的;为了方便起见,任何 COM 对象都可以自由地对每个对象进行 ref 计数,但结果是,如果要包装对象,则必须假设最严格的情况。因此,您不能假设任何给定的 IUnknown 都将用于该对象上的所有 addrefs/releases:您确实需要单独跟踪每个接口(interface)。

规范的 IUnknown - 您通过 QI'ing for IUnknown 返回的那个 - 可以是任何接口(interface) - 甚至是仅用于充当身份的专用 IUnknown! - 只要每次都返回相同的二进制指针值。所有其他接口(interface)都可以以任何方式实现;通常每次都返回相同的值,但是 COM 对象可以合法地在每次有人 QI 的 IFoo 时返回一个新的 IFoo。或者甚至保留 IFoos 的缓存并随机返回一个。

...然后您需要处理聚合 - 基本上,COM 根本没有强大的对象概念,它都是关于接口(interface)的。在 COM 中,对象只是碰巧共享相同规范 IUnknown 的接口(interface)的集合:它们可能在幕后被实现为单个 C/C++ 对象,或者作为呈现一个外观的一系列相关 C/C++ 对象。 '单个 COM 对象'。


说了这么多,考虑到:

I'm tracing the state of various components (including all COM objects) of this software for the sake of debugging

这是一种替代方法,可能会产生一些有用的数据进行调试。

这里的想法是 COM 对象的许多实现会将引用计数作为返回值返回给 Release() - 所以如果它们返回 0,那么这就是接口(interface)可能已被释放的线索。

但不能保证:如 MSDN状态:

The method returns the new reference count. This value is intended to be used only for test purposes.

(添加了重点。)

但这显然是你在这里所做的。

因此,假设您拥有调用代码,您可以做的一件事是用一个名为 MyRelease() 的内联或类似调用 release 的内联替换 Release() 调用,如果它注意到返回值为 0,然后注意到接口(interface)指针现在可能已被释放 - 将其从表中删除,将其记录到文件中,等等。

一个主要的警告:请记住,COM 没有弱引用的概念,即使您尝试将某些东西组合在一起。就 COM 而言,使用未经过 AddRef() 处理的 COM 接口(interface)指针是非法的;因此,如果您将接口(interface)指针值保存在任何类型的列表中,那么您唯一应该这样做的是将它们视为不透明的数字以进行调试(例如,将它们记录到文件中,以便您可以将创建与销毁相关联,或跟踪你有多少优秀的),但不要试图将它们用作实际的接口(interface)指针。

同样,请记住,没有什么要求 COM 对象遵循返回 refcount 的约定;因此请注意,您可能会看到一些看起来像错误但实际上只是 Release 的实现,只是碰巧总是返回 0(或者 rand(),如果你特别不走运的话!)

关于c++ - 如何在 C++ 中维护对 COM 对象的弱引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6120854/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com