2016-11-19 286 views
0

当您在运行对象表中注册一个带有零标志的COM对象(请求弱引用)时,ROT会将引用计数递增1.从ROT获取对象的行为会将引用计数再增加一个。一旦释放了该对象,该对象就会保持活动状态,并且引用计数至少为1。它在ROT中的注册也不会在检索时被神奇地撤销。运行对象表如何实现弱引用?

这是如何弱?与强大的注册有什么不同?

强注册遵循相同的模式 - 注册和检索增加一个参考计数。

ROT返回到in-apartment客户端的接口指针不是代理; ROT无法知道我释放了我检索到的接口指针。

+0

从[IRunningObjectTable :: Register](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680747.aspx):*“对于一个弱注册(ROTFLAGS_REGISTRATIONKEEPSALIVE未设置)时,ROT将释放每当最后强有力的参考对象被释放。对于强注册(ROTFLAGS_REGISTRATIONKEEPSALIVE集)的对象时,ROT防止物体被破坏,直至对象登记明确撤销。“* – IInspectable

+0

我读过。你能解释一下,“最后一个强烈的对象被释放”是什么意思?如果你刚刚从ROT获得它,然后释放它,它不会释放该对象。在疲软的情况下,ROT就像在强大的情况下持有一个参考。 –

+0

我理解它的方式(我不得不承认我从未做过额外的检查)是,强大的注册请求'ROTFLAGS_REGISTRATIONKEEPSALIVE'确保ROT持有有效的引用,无论如何。如果没有这个标志,它会以类似的方式开始(没有别的办法,尤其是那些文档说最初的'AddRef'总是会发生的),但是API保留在任何时候释放条目的权利,尤其是。特定事件,如发布代理。 –

回答

1

真正从ROT行为去除不仅依赖从ROTFLAGS_REGISTRATIONKEEPSALIVE标志,但也有(以及如何)你的对象实现IExternalConnection

特殊说明的@IInspectable唯一的 - 是的,这一切都是无证,不支持的,可以改变 - 所以请不要阅读更多)。

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

万一ROTFLAGS_REGISTRATIONKEEPSALIVE已经在所谓的报名时间IExternalConnection::AddConnection。所以我们已经有1个外部连接。无ROTFLAGS_REGISTRATIONKEEPSALIVE - 此方法未被调用。每次

,当有人打电话IRunningObjectTable::GetObject!从另一个公寓)的CRemoteUnknown::RemAddRef叫我们的进程。此方法只有在我们注册没有ROTFLAGS_REGISTRATIONKEEPSALIVE标志的情况下调用IExternalConnection::AddConnection标志。每次

当我们最终Release对象(的代理,从以前的GetObject通话获得!) - CRemoteUnknown::RemReleaseWorker叫在我们当地的过程。它在内部呼叫IExternalConnection::ReleaseConnection只有的情况下没有ROTFLAGS_REGISTRATIONKEEPSALIVE对象。 IExternalConnection的默认实现调用CStdMarshal::Disconnect - >InternalIrotRevoke当外部参考(非tottal对象引用)达到0和fLastReleaseCloses == TRUE - 结果我们的对象从ROT被撤销。但如果我们自己实施IExternalConnection,我们可以打电话或不打电话CoDisconnectObject,所以我们可以从ROT撤销。

最后当我们直接或间接调用IRunningObjectTable::Revoke COM调用IExternalConnection::ReleaseConnection如果我们注册ROTFLAGS_REGISTRATIONKEEPSALIVE

这样的结论:如果我们用ROTFLAGS_REGISTRATIONKEEPSALIVE注册

- IExternalConnection::AddConnection将在注册时只调用一次(真可谓说n+1时间和n时间 - ReleaseConnection - 但这里面所有IRunningObjectTable::Register调用) 。当有人从ROT得到我们的对象 - 我们将没有通知关于此。当我们拨打IRunningObjectTable::Revoke时,最后IExternalConnection::ReleaseConnection也只会被调用一次。

从另一方面,如果我们不使用ROTFLAGS_REGISTRATIONKEEPSALIVE标志 - IExternalConnection方法将RegisterRevoke不叫。但它会在IRunningObjectTable::GetObject最终Release称为的对象代理)多时间。如果我们自己没有执行IExternalConnection或者当外部参考文献达到0时致电CoDisconnectObject并且fLastReleaseCloses - 我们将从ROT中删除。但我们免费不叫CoDisconnectObject(在这种情况下,行为会像我们使用ROTFLAGS_REGISTRATIONKEEPSALIVE),或者说把它叫做一定条件下。

优势 - 我们可以跟踪每一个我们的对象使用的情况下,没有ROTFLAGS_REGISTRATIONKEEPSALIVE标志,并通过自我决定的,当外部裁判达到0或不需要断开。

最后 - 如果我们调用IRunningObjectTable::GetObject从同一公寓,我们称之为IRunningObjectTable::Register - 我们有没有代理服务器,而是直接对象指针。在这种情况下当然不会调用IExternalConnection方法

+0

现在它是有道理的。我已经使用户外客户端测试了场景,当它断开连接时,对象被一直释放到零。 –

+0

@SevaAlekseyev - 是的,离开公寓客户(真正的代理)和公寓内客户之间的根本不同。然而,为了最好的理解情况 - 很好的实现'自我对象上的IExternalConnection'(只有2个简单的方法),在这之后会很清楚 – RbMm