1

When you register a COM object in the Running Object Table with a zero flag (requesting a weak ref), the ROT increments the ref count by 1. The act of getting an object from the ROT increases the ref count by one more. Once that one is freed, the object stays alive with a ref count of at least one. Its registration in the ROT isn't magically revoked upon retrieval, either.

How is that weak? How is that different from strong registration?

Strong registration follows the same pattern - both registering and retrieval increments the ref count by one.

The interface pointer that the ROT returns to in-apartment clients is not a proxy; the ROT has no way of knowing that I've freed my retrieved interface pointer.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • From [IRunningObjectTable::Register](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680747.aspx): *"For a weak registration (ROTFLAGS_REGISTRATIONKEEPSALIVE not set), the ROT will release the object whenever the last strong reference to the object is released. For a strong registration (ROTFLAGS_REGISTRATIONKEEPSALIVE set), the ROT prevents the object from being destroyed until the object's registration is explicitly revoked."* – IInspectable Nov 19 '16 at 17:12
  • I've read that. Can you please explain what does "last strong reference to the object is released" mean? If you just get the it from the ROT and then release, it doesn't free the object. In the weak scenario, the ROT holds a reference just like in the strong one. – Seva Alekseyev Nov 19 '16 at 17:36
  • The way I understand it (and I have to admit I never did additional checking) is that request of strong registration `ROTFLAGS_REGISTRATIONKEEPSALIVE` makes it sure that ROT holds a valid reference no matter what. Without the flag, it starts a similar way (there is simply no other way, esp. that documentation states that initial `AddRef` always happen), but the API retains the right to release the entry at any time, esp. on specific event such as release of a proxy. – Roman R. Nov 19 '16 at 18:06
  • A weak reference is a one-time-use scenario. The client app does whatever it needs to do to get the server started and retrieves the object reference. Once it is done, its last Release() call automatically also removes it from the ROT, no more references left. The server knows it can stop running. OLE is pretty dead so no real idea how practical this still is. – Hans Passant Nov 20 '16 at 14:55
  • in this context 'weak reference' == 'external reference' - reference count for object from another com apartment – RbMm Nov 20 '16 at 18:31

1 Answers1

2

really removal from ROT behavior dependent not only from ROTFLAGS_REGISTRATIONKEEPSALIVE flag but also are (and how) your object implemented IExternalConnection

( special note for @IInspectable only - yes all this is undocumented, unsupported, can changed - so please not read more ).

when we register object in ROT com always query him for IExternalConnection interface. if object not implemented it - used default implementation.

in case ROTFLAGS_REGISTRATIONKEEPSALIVE already at registration time IExternalConnection::AddConnection called. so we already have 1 external connection. without ROTFLAGS_REGISTRATIONKEEPSALIVE - this method not called.

every time when somebody call IRunningObjectTable::GetObject (! from another apartment) the CRemoteUnknown::RemAddRef called in our process. this method call IExternalConnection::AddConnection only if we register without ROTFLAGS_REGISTRATIONKEEPSALIVE flag .

every time when we final Release object (!on proxy, obtained from previous GetObject call ) - CRemoteUnknown::RemReleaseWorker called in our local process. and it internally call IExternalConnection::ReleaseConnection only in case no ROTFLAGS_REGISTRATIONKEEPSALIVE on object. default implementation of IExternalConnection called CStdMarshal::Disconnect -> InternalIrotRevoke when external reference (not tottal object reference) reach 0 and fLastReleaseCloses == TRUE - as result our object is revoked from ROT. but if we implemet IExternalConnection by self we can call or not call CoDisconnectObject so we can be revoked or not from ROT.

and finally when we direct or indirect call IRunningObjectTable::Revoke com call IExternalConnection::ReleaseConnection if we register with ROTFLAGS_REGISTRATIONKEEPSALIVE .

so conclusion:

if we register with ROTFLAGS_REGISTRATIONKEEPSALIVE - IExternalConnection::AddConnection will be called only once at registration time (really can be called say n+1 time and n time - ReleaseConnection - but all this inside IRunningObjectTable::Register call.). when somebody get our object from ROT - we will be not notified about this. and finally IExternalConnection::ReleaseConnection will be called also only once when we call IRunningObjectTable::Revoke.

from the other hand, if we not use ROTFLAGS_REGISTRATIONKEEPSALIVE flag - IExternalConnection methods will be not called on Register and Revoke. but it will be multiple time called on IRunningObjectTable::GetObject and final Release (on object proxy). if we not implemented IExternalConnection yourself or call CoDisconnectObject when external refs reach 0 and fLastReleaseCloses - we will be removed from ROT. but we free not call CoDisconnectObject (in this case behavior will be like we use ROTFLAGS_REGISTRATIONKEEPSALIVE) or say call it under some condition.

advantage - we can track every our object use in case no ROTFLAGS_REGISTRATIONKEEPSALIVE flag and decide by self are need disconnect when external refs reach 0 or not.

and the last - if we call IRunningObjectTable::GetObject from same apartment where we call IRunningObjectTable::Register - we got not proxy, but direct object pointer. in this case of course will be no calls to IExternalConnection methods

RbMm
  • 31,280
  • 3
  • 35
  • 56
  • Now it makes sense. I've tested the scenario with an out-of-apartment client, when it disconnects, the object is released all the way to zero. – Seva Alekseyev Nov 21 '16 at 15:27
  • @SevaAlekseyev - yes, fundamental different here between out-of-apartment client (really proxy) and in-apartment clients. however for the best understand situation - good be implement `IExternalConnection` on self object (only 2 simply methods) and will be very clear after this – RbMm Nov 21 '16 at 15:31