Examine reference counting issues under aggregation.
COM Reference Counting
Using the OuterCOMObj and InnerCOMObj objects from the last lesson, let's examine some issues related to reference counting in an aggregated object. We also need to extend our example to include COM
servers. Assume that both OuterCOMObj and InnerCOMObj are implemented in in-process servers. OuterCOMObj is in
OCOMSrv.dll, InnerCOMObj is in ICOMSrv.dll.
Recall that COM objects use a reference counting mechanism to track interface and object usage to support
lifetime management of objects and servers.
The following code fragment depicts a client using the aggregation of OuterCOMObj and InnerCOMObj (remember, the client is not aware of the aggregation).
In the code fragment above, the client correctly uses and releases a pointer to interface IF2. However, if we were to implement reference counting and server unloading as we did before (in COM Fundamentals I), we could have a problem. When the client calls IF2::Release, the call goes directly into InnerCOMObj, which decrements IF2's reference counter. COM will call DllCanUnloadNow in the inner COM server (ICOMSrv.dll) to see if the server can be unloaded. DllCanUnloadNow will see that all reference counters have a zero value and return S_OK, and COM will unload the server. Using these implementation techniques for reference counting means that none of this activity is visible to the outer COM object. When the inner COM server (ICOMSrv.dll) is unloaded, the inner COM object (InnerCOMObj) is removed from memory. We no longer have an aggregation of both objects, and OuterCOMObj thinks InnerCOMObj is still active.
This scenario illustrates another problem that must be solved when aggregating objects: How can aggregated COM objects work with the outer COM object to support lifetime management? Aggregation requires that all the COM objects involved must act like one object. All objects participating in the aggregation must support reference counting in such a way that all object lifetimes are synchronized. This means that all inner objects and the outer object are created and destroyed at the same time. We will answer this question and explain how interface navigation is supported in the next few lessons.