Search code examples
c++pointerscom

Trying to understand Pointers to Interfaces and IUnknown::QueryInterface in C++


I'm currently learning about Component Object Model (COM) and found myself a little bit confused about Interfaces. Got several questions:

1.- Is there any difference between a pointer to a Class and a pointer to an Interface?

2.- Why is that we want to access to an Interface throughout a pointer to it, and not through the instance of the Interface directly?

3.- In IUnknown - Win32 apps | Microsoft Learn there is some documentation about IUnknown::QueryInterface. What does it stores in ppvObject? If we dereference ppvObject should we always get the same pointer that we used to call QueryInterface independently from the Interface we are querying as long as the Interface is implemented by the calling object?

For example, if we run pMyObject->QueryInterface(SomeRIID, &pvObject); then pvObject will be equal to pMyObject as long as pMyObject is a pointer to a class that implements the Interface associated to SomeRIID?


Solution

    1. COM is language agnostic, so we always get a reference to a COM interface. The word "class" you use here is bound to the C++ language. How the interface reference was obtained (from a C++ class maybe if the oject implementation is C++) is irrelevant. Some interfaces are obtained from a coclass, others from method calls, including QueryInterface. In general, we describe interfaces and coclasses in IDL files precisely because COM is language agnostic.

    2. see 1. If by "instance of the Interface" you mean the C++ vtable/struct behind all this, it's again because it's all language agnostic. But you do get a "COM vtable" ("object layout") behind that pointer, as the COM interface is a binary contract. That binary contract is a defined ordered list of methods which a defined method signature (a defined ordered list of parameters each with a defined type, and a defined return type, or void), and a defined calling convention (usually stdcall), for each method.

    3. The IUnknown remarks section should contain everything you want to know:

    For any given COM object [...], a specific query for the IUnknown interface on any of the object's interfaces must always return the same pointer value. This enables a client to determine whether two pointers point to the same component by calling QueryInterface with IID_IUnknown and comparing the results.

    It is specifically not the case that queries for interfaces other than IUnknown (even the same interface through the same pointer) must return the same pointer value.

    PS: ok, it is no coincidence that the Win32 COM object layout matches closely the C++ object layout....