September 11th, 2020

The macros for declaring COM interfaces, revisited: C++ implementation

Last time, we looked at the macros for declaring COM interfaces and how they expand when compiled for C++. Now we’ll look at the macros you use for implementing the interface.

class Class : public ISomething
{
public:
    // *** IUnknown ***
    IFACEMETHOD(QueryInterface)(REFIID riid, void** ppv);
    IFACEMETHOD_(ULONG, AddRef)();
    IFACEMETHOD_(ULONG, Release)();

    // *** ISomething ***
    IFACEMETHOD(Method1)();
    IFACEMETHOD_(int, Method2)();
    IFACEMETHOD(Method3)(int iParameter);
};

The IFACEMETHOD and IFACEMETHOD_ macros are used for declaring that your class implements a particular method. The result of the macro expansion is this:

class Class : public ISomething
{
public:
    // *** IUnknown ***
    /* IFACEMETHOD(QueryInterface)(REFIID riid, void** ppv); */
    __override virtual __declspec(nothrow)
    HRESULT QueryInterface(REFIID riid, void** ppv);

    /* IFACEMETHOD_(ULONG, AddRef)(); */
    __override virtual __declspec(nothrow)
    ULONG AddRef();

    /* IFACEMETHOD_(ULONG, Release)(); */
    __override virtual __declspec(nothrow)
    ULONG Release();

    // *** ISomething ***
    /* IFACEMETHOD(Method1)(); */
    __override virtual __declspec(nothrow)
    HRESULT Method1();

    /* IFACEMETHOD_(int, Method2)(); */
    __override virtual __declspec(nothrow)
    int Method2();

    /* IFACEMETHOD(Method3)(int iParameter); */
    __override virtual __declspec(nothrow)
    HRESULT Method3(int iParameter);
};

Analogous with the STDMETHOD and STDMETHOD_ macros, you use the underscore version of the IFACEMETHOD macro (IFACEMETHOD_) if the return value is not HRESULT.

The __override annotation is understood by static analysis tools like PREfast. The annotation means that the static analysis tool should verify that function declaration overrides an identical method in the base class.

The __override annotation was introduced as part of SAL, the Microsoft Standard Annotation Language. It has been made redundant by C++11’s override keyword, but the macros still generate them just the same.

In practice, therefore, you are probably going to write

    IFACEMETHOD(Method1)() override;

to inform both the static analysis tool and the C++ compiler of your intention to override a method from the base class.

When it comes time to define the method, you do it with the IFACEMETHODIMP macro:

IFACEMETHODIMP Class::Method1()
{
    ...
}

Use IFACEMETHODIMP_(T) if the return type is not HRESULT.

The above expands to

__override HRESULT __stdcall Class::Method1()
{
    ...
}

If you want to implement the method inline, then you can put the implementation directly after the declaration inside the class definition.

class Class : public ISomething
{
public:
    ...
    IFACEMETHOD(Method1)() override { ... }
    ...
};
Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

6 comments

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

  • carranza howell

    😌

  • Giorgi Chakhidze

    Next: “Declaring COM interfaces, revisited: C# implementation”

    • Paulo Pinto

      Yeah, it is quite unfortunate that while C++ has the ability to provide a nice C# like experience, see C++ Builder, Microsoft teams insist in forcing us into this kind of boilerplate (C++/WinRT hardly improved it, on the contrary with the primitive tooling for IDL files).

    • Henke37

      Given that C# has COM integration, that’s actually a good idea.

      • MGetz

        Last I checked that was literally just marking the class as [ComVisible(true)] albeit with some gotchas as far as what should and shouldn’t be done. That said… there are lots of ways for the developer to control what is and isn’t exported, and how all that happens.

  • c_linkage

    Examples like the one above showing how C++ implemented interfaces (especially the part about inline declaration of function bodies) was what I found to be confusing about COM back when I had only a year of C++ experience back in the late 90s.

    The COM specification and the Don Box book go to great lengths talking about how interfaces were separated from implementation. The fact that the reference count was attached to the interface and not...

    Read more