If you know what interface you want, just pass it directly to CoCreateInstance

Raymond Chen

A pattern I sometimes see is calling Co­Create­Instance for an interface, and immediately turning around and querying for another interface, and never using the original interface.¹

wil::com_ptr<IWidget> widget;
RETURN_IF_FAILED(
    CoCreateInstance(CLSID_Widget, nullptr,
        CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&widget)));

wil::com_ptr<IServiceProvider> provider;
RETURN_IF_FAILED(
    widget->QueryInterface(IID_PPV_ARGS(&provider)));

// use the service provider, ignore the widget

There’s rarely any need to request one interface, then immediately exchange it for another interface. You may as well go directly for the interface you want:

wil::com_ptr<IServiceProvider> provider;
RETURN_IF_FAILED(
    CoCreateInstance(CLSID_Widget, nullptr,
        CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&provider)));

// use the service provider

For non-local interfaces, collapsing the request into a single call avoids a round trip to the server.

The only case I can think of where the initial interface is significant is if you want to ensure that the object supports the intermediate interface, even though you aren’t going to be using it right now.

// Factories must support IServiceProvider.
wil::com_ptr<IServiceProvider> provider;
RETURN_IF_FAILED(
    CoCreateInstance(factoryClassId, nullptr,
        CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&provider)));

wil::com_ptr<IWidget> widget;
RETURN_IF_FAILED(
    provider->QueryInterface(IID_PPV_ARGS(&widget)));

// use the widget, ignore the IServiceProvider for now

In that case, you can still avoid a round trip to the server by using Co­Create­Instance­Ex to request multiple interfaces at once.

MULTI_QI mqi[2] = {
    { &__uuidof(IWidget), nullptr, 0 },
    { &__uuidof(IServiceProvider), nullptr, 0 },
};

RETURN_IF_FAILED(CoCreateInstanceEx(
    factoryClassId, nullptr, CLSCTX_LOCAL_SERVER,
    nullptr, ARRAYSIZE(mqi), mqi));

wil::com_ptr<IWidget> widget;
widget.attach(mqi[0].pItf);

wil::com_ptr<IServiceProvider> provider;
provider.attach(mqi[1].pItf);

if (hr != S_OK) {
    // Failed to get at least one interface.
    return E_NOINTERFACE;
}

You can refer to my earlier series on MULTI_QI for further discussion.

¹ Note that I’m using WIL only for its smart pointer class and still programming to the ABI for the most part. WIL itself contains wrappers for many of the patterns here, but this article is really about the pattern and not the WIL wrappers.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • GL 0

    Another case is when you decide to respond to a QueryInterface by aggregating a stateless helper inner object without caching the inner object. In that case, the inner object must be created for IUnknown, then immediately queried for the desired interface, and have the IUnknown released.

    Last time I checked, the docs say aggregation is not supported for local servers or remote servers. Since it doesn’t say the cross-apartment same-process case, I assume it’s supported — and if so, I’ve been wondering the reason of stopping at process boundary…

  • Ian Boyd 0

    I thought one of the COM object Identity rules is that anytime you ask for IUnknown, it is required to represent the same object. But if you ask for another interface it can be a separate object.

    But IUnknown has a special, consistent, identity, that must always be the same pointer.

    So I always try to get IUnknown first, then let it spider out from there, as i Query for other Interfaces, and it possibly constructs other objects that implement other Interfaces.

    • Raymond ChenMicrosoft employee 0

      While it’s true that IUnknown is special, you rarely rely on the special-ness, and if you really need to, you can QI for it at the point you need it. (Which you should be doing in general because you don’t know whether any random IUnknown given to you is the special identity-defining one.)

  • Letao Wang 0

    I’m guilty of this. On the other hand, I’m also guilty of writing a COM class factory that doesn’t support this usage pattern (it only succeeded if you CoCreate(CWidget, IWidget), and you can QI the IWidget to IServiceProvider, but it did not succeed if you CoCreate(CWidget, IServiceProvider)). It was a case of “I had no idea COM could do this”.

    • Henke37 0

      Yeah, that breaks the rules. A COM object must be consistent about which interfaces it supports.

Feedback usabilla icon