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.
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