QISearch

This function gives consistency to implementations of the QueryInterface method by standardising a lookup table of the supported interfaces.

Declaration

HRESULT
QISearch (
    VOID *that,
    LPCQITAB pqit,
    REFIID riid,
    VOID **ppv);

Since the QITAB structure is apparently used only for this function, its format is as well given here.

typedef struct {
    const IID *piid;
    int dwOffset;
} QITAB, *LPQITAB, const *LPCQITAB; 

Parameters

The that argument provides the address of an object that supports one or more interfaces.

The pqit argument provides the address of an array of QITAB structures that describe the supported interfaces. The array ends with the first QITAB structure whose piid member is NULL. A QITAB structure for the IUnknown interface is unnecessary.

The riid argument is a reference to an IID for the requested interface.

The ppv argument addresses a variable that is to receive the interface pointer, i.e., an address for use of the given object through the requested interface.

Return Value

The function returns zero for success, else an error code.

Behaviour

If the ppv argument is NULL, no interface pointer can be returned whether the requested interface is supported or not, and the function returns E_POINTER.

If the requested interface is not supported, the function returns E_NOINTERFACE and stores NULL as the interface pointer.

The requested interface is recognised as supported if the riid matches the piid member for some QITAB in the array or if the riid is for IUnknown. If the requested interface is represented in a QITAB, then the corresponding dwOffset member measures the bytes from the start of the object to the object’s pointer to the virtual function table for the requested interface. If the interface is IUnknown, then the function takes the dwOffset from the first QITAB.

Success implies a call to the AddRef method of the requested interface.

Example

A call to QISearch, along with a properly defined Query Interface Table (QITAB array), typically suffices for a complete implementation of a QueryInterface method. Consider the following example of a class CTest that offers the interfaces ITest1 and ITest2. If we allow the following macro to help generate the dwOffset members

#define VTABLE_OFFSET(cls,iface)    ((PCHAR)(iface *)(cls *) 1 - (PCHAR) 1)

then a complete implementation of the QueryInterface method for class CTest is given by

STDMETHODIMP CTest :: QueryInterface (REFIID riid, PVOID *ppv)
{
    static const QITAB qit [] = {
        {&IID_ITest1, VTABLE_OFFSET (CTest, ITest1)},
        {&IID_ITest2, VTABLE_OFFSET (CTest, ITest2)),
        {NULL, 0}
    };

    return QISearch (this, qit, riid, ppv);
}

For a project with many classes that each implement multiple interfaces, use of QISearch could easily save appreciable space, as well as help with tidiness and consistency.

Availability

The QISearch function is exported from SHLWAPI.DLL as ordinal 219 in version 5.00 and higher.

Though this function dates from as long ago as 1999, it was still not documented by Microsoft in the MSDN Library at least as late as the CD edition dated January 2004.

Consultation of the MSDN on-line has shown that the function has got documented meanwhile, apparently some time during 2004. The names QISearch and QITAB had been known from readily available symbol files for various releases of SHLWAPI, but all names in this article now follow Microsoft’s documentation.

Microsoft’s documentation is marked by an insistence that a “significantly better” helper is provided by the Active Template Library (ATL). True, a programmer who is anyway working within the framework provided by the ATL would be mad to use QISearch instead of the corresponding ATL helper. But it is at least equally true that a programmer who sees no other benefit to the ATL would be mad to buy into its (substantial) overhead just for its help with QueryInterface.