Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
A version of this page is also available for
4/8/2010

The methods in IUnknownenable an application to manage the component's reference count and query for interfaces on the component. For this to work properly with aggregated COM components, the IUnknowninterface must be delegated to the outer component in the aggregation.

Reference Count

The reference count is an internal variable, incremented in the IUnknown::AddRefmethod and decremented in the IUnknown::Releasemethod. The base classes manage the reference count and synchronize access to the reference count among multiple threads.

Interface Queries

Querying for an interface is also straightforward. The caller passes two parameters: an interface identifier (IID), and the address of a pointer. If the component supports the requested interface, it sets the pointer to the interface, increments its own reference count, and returns S_OK. Otherwise, it sets the pointer to NULL and returns E_NOINTERFACE. The following example shows the general outline of the IUnknown::QueryInterfacemethod. Component aggregation, described in the next section, introduces some additional complexity.

Copy Code
if (IID == IID_IUnknown)
	set pointer to (IUnknown *)this
	AddRef
	return S_OK

else if (IID == IID_ISomeInterface)
	set pointer to (ISomeInterface *)this
	AddRef
	return S_OK

else if ... 

else
	set pointer to NULL
	return E_NOINTERFACE

The only difference between the QueryInterfacemethod of one component and the QueryInterfacemethod of another is the list of IIDs that each component tests. For every interface that the component supports, the component must test for the IID of that interface.

Aggregation and Delegation

Component aggregation must be transparent to the caller. Therefore, the aggregate must expose a single IUnknowninterface, with the aggregated component deferring to the outer component's implementation. Otherwise, the caller would see two different IUnknowninterfaces in the same aggregate. If the component is not aggregated, it uses its own implementation.

To support this behavior, the component must add a level of indirection. A delegating IUnknowndelegates the work to the appropriate place: to the outer component, if there is one, or to the component's internal version. A nondelegating IUnknowndoes the work, as described in the previous section.

The delegating version is public and keeps the name IUnknown. The nondelegating version is renamed INonDelegatingUnknown. This name is not part of the COM specification, because it is not a public interface.

When the client creates an instance of the component, it calls the IClassFactory::CreateInstancemethod. One parameter is a pointer to the aggregating component's IUnknowninterface, or is NULL if the new instance is not aggregated. In its constructor method, the component uses this parameter to store a member variable that indicates which IUnknowninterface to use, as shown in the following example.

Copy Code
CMyComponent::CMyComponent(IUnknown *pOuterUnknown)
{
	if (pOuterUnknown == NULL)
		m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
	else
		m_pUnknown = pOuterUnknown;

	[ ... more constructor code ... ]
}

Each method in the delegating IUnknowncalls its nondelegating counterpart, as shown in the following example.

Copy Code
HRESULT QueryInterface(REFIID iid, void **ppv) 
{
	return m_pUnknown->QueryInterface(iid, ppv);
}

By the nature of delegation, the delegating methods look identical in every component. Only the nondelegating versions change.

See Also