Fre*_*abe 13 c++ windows com weak-references
在我的应用程序中,我正在挂钩创建COM对象的各种函数(例如CoCreateInstanceEx
),以便在创建某个对象时得到通知.我正在跟踪所有创建的对象std::list
,我正在迭代该列表以执行各种操作(例如检查已激活的OLE对象).
这个问题是,现在,每当添加一个IUnknown
指向我的列表的指针时,我会调用IUnknown::AddRef
它以确保它在我跟踪它时不会被破坏.这不是我真正想要的; 对象的生命周期应该与没有我的跟踪代码一样长(或短),所以我宁愿保持对象的弱引用.每当删除对某个跟踪的COM对象的最后一个引用(因此对象被销毁)时,我希望得到通知,以便我可以更新我的簿记(例如,通过在我的列表中设置指针NULL
).*
最好的方法是什么?现在,我正在修补所有创建对象的(第一个)VTable,以便IUnknown::Release
通过第一个vtable 的调用得到通知.但是,这不适用于从多个接口继承的COM接口(因此有多个vtable),但我不确定这是否真的是一个问题:给定实现QueryInterface的规则,应该总是只IUnknown
返回一个用IUnknown::QueryInterface
,对不对?所以我可以做到这一点然后修补那个vtable.
此外,这种方法也有点毛茸茸,因为它涉及创建产生一些代码的thunk.到目前为止我只为32位实现了这个.这不是一个大问题,但仍然存在.
我真的想知道是否有一种更优雅的方式来对COM对象进行弱引用.有人知道吗?
*:我要解决的下一件事是,如果我有活动迭代器(我使用自定义迭代器对象)遍历COM对象列表,那么这项工作正常.我可能需要跟踪活动迭代器,一旦完成最后一个迭代器,从列表中删除所有空指针.或类似的东西.
这不是一个答案,而是一系列问题,为什么这是一件非常棘手的事情 - 我将其作为答案,因为这里的信息太多,无法在评论中容纳:)
我的理解是,COM 中不存在弱引用的概念。您已经通过 IUnknown 获得了引用计数,这就是 COM 处理对象生命周期管理的方式的总和。严格来说,超出此范围的任何内容都不是 COM。
(.Net 确实支持这个概念,但它有一个实际的基于 GC 的内存管理器来提供适当的支持,并且可以以不同于内存中常规引用的方式处理 WeakRef 对象。但 COM 假设的非常简单的世界并非如此,它是一个简单的内存和指针的世界,仅此而已。)
COM 指定引用计数是针对每个接口的;为了方便起见,任何 COM 对象都可以自由地对每个对象进行引用计数,但结果是,如果您要包装对象,则必须假设最严格的情况。因此,您不能假设任何给定的 IUnknown 将用于该对象上的所有 addrefs/releases:您确实需要单独跟踪每个接口。
规范的 IUnknown - 通过 QI'ing 获取 IUnknown 得到的接口 - 可以是任何接口 - 甚至是仅用于充当身份的专用 IUnknown!- 只要每次返回相同的二进制指针值。所有其他接口都可以以任何方式实现;通常每次都会返回相同的值,但是每次有人 QI 获取 IFoo 时,COM 对象都可以合法地返回一个新的 IFoo。或者甚至保留 IFoos 缓存并随机返回一个。
...然后你需要处理聚合 - 基本上,COM 根本没有强大的对象概念,它都是关于接口的。COM 中的对象只是碰巧共享相同规范 IUnknown 的接口的集合:它们可能在幕后实现为单个 C/C++ 对象,或者作为呈现外观的一系列相关 C/C++ 对象。 “单个 COM 对象”。
说了这么多,考虑到:
为了调试,我正在跟踪该软件的各个组件(包括所有 COM 对象)的状态
这是一种替代方法,可能会产生一些有用的数据进行调试。
这里的想法是,COM 对象的许多实现将返回引用计数作为 Release() 的返回值 - 因此,如果它们返回 0,则表明该接口可能已被释放。
然而,这并不能得到保证:正如MSDN所说:
该方法返回新的引用计数。该值仅用于测试目的。
(强调已添加。)
但这显然就是你在这里所做的。
因此,假设您拥有调用代码,您可以做的一件事是将 Release() 的调用替换为名为 MyRelease() 的内联函数或类似的将调用release的函数,并且如果它注意到返回值为 0,则指出接口指针现在可能已被释放 - 将其从表中删除,将其记录到文件中,等等。
一个重要的警告:请记住,COM 没有弱引用的概念,即使您尝试将某些东西组合在一起。就 COM 而言,使用未经 AddRef() 处理的 COM 接口指针是非法的;因此,如果您将接口指针值保存在任何类型的列表中,您唯一应该做的就是将它们视为不透明的数字以进行调试(例如,将它们记录到文件中,以便您可以将创建与销毁相关联,或跟踪有多少个未完成的),但不要尝试将它们用作实际的接口指针。
再次请记住,没有什么要求 COM 对象遵循返回引用计数的约定;因此请注意,您可能会看到一些看起来像错误但实际上只是 Release 的实现,只是碰巧总是返回0 (或 rand(),如果您特别不幸的话!)
归档时间: |
|
查看次数: |
1515 次 |
最近记录: |