Search code examples
c++winapicomshell-extensionsqueryinterface

Is calling QueryInterface() ever absolutely necessary in COM?


In this C++/COM shell extension tutorial, the programmer demonstrates (for purposes of edification) that you can forego calling QueryInterface() and simply pass around a general object instead. At least that works when implementing DllGetClassObject(). He says the purpose of QueryInterface() is just to have each object speak for itself as to whether it supports a given interface.

Microsoft, meanwhile, seems to say that QueryInterface() is necessary to get a pointer to a specific interface on an object.

So to what extent is QueryInterface() necessary? Is there any time when calling QueryInterface() is absolutely essential, and without it the code wouldn't work? Or is getting the object itself technically sufficient, as the video tutorial suggests?


Solution

  • No, as a general rule you cannot skip calling QueryInterface unless you know the interface pointer you have is already correct.

    If we imagine a object that implements IFoo and IBar the layout might look something like this:

    VT
      IFoo_QueryInterface(...)
      IFoo_AddRef()
      IFoo_Release()
      IFoo_FooFight(int, int)
    VT
      IBar_QueryInterface(...)
      IBar_AddRef()
      IBar_Release()
      IBar_BarBarBar(int)
    

    A instance of the object might point to IFoos v-table pointer or IBars v-table pointer. Calling the 4th method without knowing which one it really is will crash because the parameter count is not the same. And even if the signature was the same, calling arbitrary methods is not a good idea.

    The video you are referring to gets away with it only because callers of DllGetClassObject usually only ask for IClassFactory. But even there it is not safe because somebody might ask for IClassFactory2 instead. Correct DllGetClassObject implementations should therefore also call QueryInterface.

    I would recommend trying to code in C instead of C++ when learning COM fundamentals, this forces you to handle all v-table indirection yourself. Take a look at this series for details.