Basic COM  «Prev  Next»
Lesson 11 QueryInterface guidelines
Objective Examine what the COM specification says about QueryInterface.

QueryInterface Guidelines and the Component Object Model

The Component Object Model (COM) specification, though largely superseded by .NET, provides detailed guidance on the QueryInterface method, which is central to COM's interface-based programming model. Below is a concise explanation of what the COM specification says about QueryInterface, based on its role and requirements.

Overview of QueryInterface

QueryInterface is a method defined in the IUnknown interface, which is the base interface for all COM objects. Every COM object must implement IUnknown, and thus QueryInterface, to enable clients to discover and access the interfaces a COM object supports.

The QueryInterface method allows a client to ask a COM object whether it supports a specific interface, identified by an Interface ID (IID). If the object supports the requested interface, it returns a pointer to that interface; otherwise, it returns an error.

Key Details from the COM Specification

1. Purpose

  • QueryInterface enables dynamic interface discovery, allowing clients to query a COM object for additional functionality without prior knowledge of the object's full capabilities.
  • It supports polymorphism by allowing objects to expose multiple interfaces, which clients can access as needed.

2. Method Signature

HRESULT QueryInterface(REFIID riid, void** ppvObject);
  • Parameters:
    • riid: A reference to the IID (a GUID) of the requested interface.
    • ppvObject: A pointer to a pointer that receives the interface pointer if the query succeeds.
  • Return Value:
    • S_OK if the interface is supported and the pointer is returned.
    • E_NOINTERFACE if the interface is not supported.
    • E_POINTER if ppvObject is NULL.

3. Rules and Requirements

  • Identity Rule: If QueryInterface returns a valid interface pointer for a given IID, subsequent calls to QueryInterface for the same IID on the same object must return the same pointer (i.e., the interface pointer must be stable).
  • Reflexivity: If an object supports an interface, calling QueryInterface for that interface's IID must succeed.
  • Symmetry: If an object supports multiple interfaces, querying for one interface and then querying for another interface from the returned pointer must work consistently.
  • Transitivity: If interface A can be queried to get interface B, and B can be queried to get interface C, then A must be able to directly query for C.
  • AddRef Requirement: If QueryInterface succeeds, it must call AddRef on the returned interface pointer to increment its reference count, ensuring proper lifetime management.

4. Implementation Responsibilities

  • The object must maintain a list of supported IIDs and their corresponding interface pointers.
  • The object must ensure thread safety for QueryInterface calls, as specified in the COM threading model (e.g., apartment-threaded or free-threaded).
  • If an object does not support the requested interface, it must set *ppvObject to NULL and return E_NOINTERFACE.

5. Usage in COM

  • Clients typically call QueryInterface to navigate between interfaces supported by a COM object. For example, a client might query for IDispatch to access automation features or for a custom interface specific to the object's functionality.
  • QueryInterface is critical for interface negotiation in scenarios like COM aggregation or when working with objects that implement multiple interfaces.

Relevance Post-COM

While .NET has largely replaced COM for new development, QueryInterface remains relevant in legacy systems, Windows APIs (e.g., DirectX, Shell), and interop scenarios where .NET components interact with COM objects via COM Interop. The principles of QueryInterface also influenced .NET's type system and interface-based design.

For further details, you can refer to the COM specification in Microsoft's official documentation, such as the COM Technical Overview or Interface Definition Language (IDL) references, available in MSDN archives. If you need specific excerpts or have a particular aspect of QueryInterface you'd like to dive deeper into, let me know!

*/ ?>
The COM specification provides significant detail about QueryInterface. Following is a summary of some of the essential points.

Values returned

All interfaces within an instance of a COM object must always return the same value for IUnknown. The reason for this is that the IUnknown pointer is used to identify an instance of a COM object uniquely. In the previous lesson, when asked for IUnknown, we returned a pointer to the first interface in the object IMyComInterface.
The COM specification does not dictate what pointer values should be returned for other interfaces. A client can call QueryInterface and ask for IID_IMyComInterface twice. The object's implementation can choose to return the same IMyComInterface pointer or create a new instance of IMyComInterface for each request. In this example, because we are using multiple inheritance of classes with pure virtual functions, we always return the same pointer value.

Symetric, reflexive, and transitive

QueryInterface is symmetric, reflexive, and transitive. These requirements are intended to enforce the idea that once a client has an interface pointer into an object, it can navigate to any other interface within the object.

Query Interface - Quiz

Click the Quiz link below to check your understanding of QueryInterface.
Query Interface - Quiz

SEMrush Software