运行 Object Table 是如何实现弱引用的?

How does Running Object Table implement weak references?

当你在 运行 对象 Table 中注册一个带有零标志的 COM 对象(请求弱引用)时,ROT 将引用计数递增 1。获取对象的行为来自 ROT 的引用计数会增加 1。一旦该对象被释放,该对象就会保持活动状态,引用计数至少为 1。它在 ROT 中的注册也不会在检索时被神奇地撤销。

怎么这么弱?这与强注册有何不同?

强注册遵循相同的模式 - 注册和检索都会将引用计数递增 1。

ROTreturns指向公寓内客户端的接口指针不是代理; ROT 无法知道我已经释放了检索到的接口指针。

真正从 ROT 行为中移除不仅取决于 ROTFLAGS_REGISTRATIONKEEPSALIVE 标志,而且还取决于(以及如何)实现您的对象 IExternalConnection

仅针对@IInspectable 的特别说明 - 是的,所有这些都没有记录,不受支持,可以更改 - 所以请不要阅读更多)。

当我们在 ROT com 中注册对象时,总是向他查询 IExternalConnection 接口。如果对象未实现它 - 使用默认实现。

万一 ROTFLAGS_REGISTRATIONKEEPSALIVE 已经在注册时间 IExternalConnection::AddConnection 打电话了。所以我们已经有 1 个外部连接。没有 ROTFLAGS_REGISTRATIONKEEPSALIVE - 未调用此方法。

每当有人打电话给 IRunningObjectTable::GetObject!从另一间公寓)时,CRemoteUnknown::RemAddRef 就会在我们的过程。此方法调用 IExternalConnection::AddConnection 仅当 我们注册 没有 ROTFLAGS_REGISTRATIONKEEPSALIVE 标志。

每次我们最终 Release 对象(!在代理上,从之前的 GetObject 调用 ) - CRemoteUnknown::RemReleaseWorker 在我们的本地进程中调用。并在对象上 IExternalConnection::ReleaseConnection only 内部调用 no ROTFLAGS_REGISTRATIONKEEPSALIVE . IExternalConnection 的默认实现调用 CStdMarshal::Disconnect -> InternalIrotRevoke 当外部引用(不是全部对象引用)达到 0 和 fLastReleaseCloses == TRUE - 结果我们的对象从 ROT 中撤销。但是如果我们自己实现 IExternalConnection 我们可以调用或不调用 CoDisconnectObject 所以我们可以从 ROT 中被撤销或不被撤销。

最后,当我们直接或间接调用 IRunningObjectTable::Revoke com call IExternalConnection::ReleaseConnection if 时,我们注册 with ROTFLAGS_REGISTRATIONKEEPSALIVE .

所以结论:

如果我们用ROTFLAGS_REGISTRATIONKEEPSALIVE注册-IExternalConnection::AddConnection只会在注册时被调用一次(真的可以调用n+1时间和n时间-ReleaseConnection - 但所有这些都在 IRunningObjectTable::Register 调用中。)。当有人从 ROT 获得我们的对象时 - 我们将不通知。最后 IExternalConnection::ReleaseConnection 也只会在我们调用 IRunningObjectTable::Revoke.

时被调用一次

另一方面,如果我们不使用 ROTFLAGS_REGISTRATIONKEEPSALIVE 标志 - IExternalConnection 方法将 不被调用 RegisterRevoke。但它将在 IRunningObjectTable::GetObject 和最终 Release 多次调用 在对象代理上).如果我们没有自己实现 IExternalConnection 或在外部引用达到 0 和 fLastReleaseCloses 时调用 CoDisconnectObject - 我们将从 ROT 中移除。但我们释放 not call CoDisconnectObject(在这种情况下,行为就像我们使用 ROTFLAGS_REGISTRATIONKEEPSALIVE)或调用它在某种条件下。

优点 - 我们可以跟踪每个对象的使用情况,以防没有 ROTFLAGS_REGISTRATIONKEEPSALIVE 标志,并自行决定在外部引用达到或不达到 0 时是否需要断开连接。

和最后一个 - 如果我们从我们呼叫 IRunningObjectTable::Register 的同一公寓呼叫 IRunningObjectTable::GetObject - 我们得到的不是代理,而是直接对象指针。在这种情况下当然不会调用 IExternalConnection 方法