Rules for Implementing QueryInterface

There are three main rules that govern implementing the IUnknown::QueryInterface method on a COM object:

  • Objects must have identity.
  • The set of interfaces on an object instance must be static.
  • It must be possible to query successfully for any interface on an object from any other interface.

Objects Must Have Identity

For any given object instance, a call to QueryInterface with IID_IUnknown must always return the same physical pointer value. This allows you to call QueryInterface on any two interfaces and compare the results to determine whether they point to the same instance of an object.

The Set of Interfaces on an Object Instance Must Be Static

The set of interfaces accessible on an object through QueryInterface must be static, not dynamic. Specifically, if QueryInterface returns S_OK for a given IID once, it must never return E_NOINTERFACE on subsequent calls on the same object; and if QueryInterface returns E_NOINTERFACE for a given IID, subsequent calls for the same IID on the same object must never return S_OK.

It Must Be Possible to Query Successfully for Any Interface on an Object from Any Other Interface

That is, given the following code:

IA * pA = (some function returning an IA *); 
IB * pB = NULL; 
HRESULT   hr; 
hr = pA->QueryInterface(IID_IB, &pB); 

the following rules apply:

  • If you have a pointer to an interface on an object, a call like the following to QueryInterface for that same interface must succeed:

    pA->QueryInterface(IID_IA, ...) 
  • If a call to QueryInterface for a second interface pointer succeeds, a call to QueryInterface from that pointer for the first interface must also succeed. If pB was successfully obtained, the following must also succeed:

    pB->QueryInterface(IID_IA, ...) 
  • Any interface must be able to query for any other interface on an object. If pB was successfully obtained and you successfully query for a third interface (IC) using that pointer, you must also be able to query successfully for IC using the first pointer, pA. In this case, the following sequence must succeed:

    IC * pC = NULL; 
    hr = pB->QueryInterface(IID_IC, &pC); 
    pA->QueryInterface(IID_IC, ...) 

Interface implementations must maintain a counter of outstanding pointer references to all the interfaces on a given object. You should use an unsigned integer for the counter.

If a client needs to know that resources have been freed, it must use a method in some interface on the object with higher-level semantics before calling IUnknown::Release.

Using and Implementing IUnknown