- Mechanics
- The Cost of Contexts
- Limiting Context
- Some Other Observations
- Summary
Some Other Observations
There are three more observations I need to make about contexts. First, for the context architecture to work, object creation requests must be routed through the SCM. If one object creates another using language-level techniques, such as operator new, the SCM is not involved. It has no chance to put the new object into an appropriate context and set up interception. As a result, objects created with language-level techniques are treated as if they were nonconfigured classes, even if they are configured or raw-configured classes with entries in the catalog. For example, one object should not create a second object using a direct call to ATL's creator plumbing, which ultimately invokes the new operator.
HRESULT CSomeCfgClass::CreateSubObject(void) { if (m_spSubObject == 0) // Creation request by-passes SCM return CSomeOtherCfgClass::CreateInstance(&m_spSubObject); return S_OK; }
In this case, the new instance of CSomeOtherCfgClass will be instantiated in its creator's context no matter what declarative attributes it specifies. To solve this problem, you must use CoCreateInstance[Ex].
HRESULT CSomeCfgClass::CreateSubObject(void) { if (m_spSubObject == 0) // Creation request is sent to SCM return m_spSubObject.CoCreateInstance(__uuidof (CSomeOtherCfgClass); return S_OK; }
If you are implementing classes in Visual Basic 6, this means they cannot reliably use operator new for object construction. VB's new operator calls CoCreateInstance if the class being instantiated is not implemented in the same DLL. If the class being instantiated is in the same DLL, new uses an internal creation mechanism instead. VB class should use CreateObject instead of new to make sure all object creation requests are routed through the SCM.
Second, for the context architecture to work, IClassFactory::CreateInstance must return a reference to a new object each time it is called. The SCM assumes that each object it creates is unique. If you implement a classic COM singleton by always returning a reference to the same object from CreateInstanceATL makes this trivial with the DECLARE_CLASSFACTORY_SINGLETON macrothe SCM will assign your object to multiple contexts, one for each creation call. Your object will have multiple proxies, channels, and stubs. How the runtime services your class uses behave in this situation varies from service to service. Suffice it to say that many of them will not provide the desired semantics. While it is possible to implement a nonconfigured or a raw-configured class as a singleton, it is far from trivial.5
Third, the life of a context is tied to the interception plumbing used to reach that context. New contexts are created by the SCM as needed to meet the requirements of new objects. A context will remain in existence as long as it contains at least one stub. A stub will remain in existence as long as there are extant proxies or a reference to it stored in the GIT. When a stub's last proxy is releasedor its GIT reference is revokedthe stub will go away, releasing its object in the process. When the last stub in a context is torn down, the context itself goes away.
Footnotes
5. It is much simpler to achieve singleton semantics using some form of logical identity to map multiple physical objects to shared state. In short, the use of a classic COM singleton is entirely outside the COM+ object-per-client model.