Search code examples
visual-studiocomstdcall

Why Doesn't MSDN or VS2015 Declare IUnknown Methods with __stdcall convention?


Apologies if this question is a bit unfocused. I am working with COM, writing some simple COM servers and objects with Visual Studio 2015 Community, under Windows 10. All COM objects must implement the IUnknown interface. VS2015's IDE will offer to implement the virtual functions of a superclass. So, if I create "Example.h" with these contents:

#include <Unknwn.h>

class MyClass : public IUnknown
{
};

And then I choose Quick Actions and Refactorings.../Implement all Pure Virtuals for class 'MyClass,' from the right-click menu, I get some generated code in my .h file:

#include <Unknwn.h>

class MyClass : public IUnknown
{
    // Inherited via IUnknown
    virtual HRESULT QueryInterface(REFIID riid, void ** ppvObject) override;
    virtual ULONG AddRef(void) override;
    virtual ULONG Release(void) override;
};

And VS2015 also provides me with a stub implementation:

#include "stdafx.h"
#include "Example.h"

HRESULT MyClass::QueryInterface(REFIID riid, void ** ppvObject)
{
    return E_NOTIMPL;
}

ULONG MyClass::AddRef(void)
{
    return 0;
}

ULONG MyClass::Release(void)
{
    return 0;
}

That's nice, but it doesn't compile. I get this error message:

error C2695: 'CFactory3::QueryInterface': overriding virtual function differs from 'IUnknown::QueryInterface' only by calling convention

I get that error message for all three methods. That makes sense, because the actual declaration for each of those methods specifies the __stdcall calling convention. Now, I can add it to the declaration of MyClass, like this:

virtual HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override;
virtual ULONG __stdcall AddRef(void) override;
virtual ULONG __stdcall Release(void) override;

That compiles just fine.

I know what calling convention to use because, first, when I use "Peek Definition," I see this:

virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
            /* [in] */ REFIID riid,
            /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) = 0;

Drilling down one more level, I see that STDMETHODCALLTYPE is simply a macro defined as __stdcall. Second, most of the tutorial material I have recommends that the IUnknown methods be implemented with the STDMETHODIMP macro (which expands to HRESULT STDMETHODCALLTYPE).

However, when I look at the MSDN Page on the IUnknown methods, no mention is made of needing any particular calling convention.

So I am left wondering why the __stdcall convention is not mentioned on the MSDN pages for the IUnknown methods, and why the VS2015 IDE didn't include it in its stub implementations of IUnknown for my subclass.

In general, how does one look up the necessary calling convention for a method or function that will be called by COM, or by any other part of Windows?


Solution

  • ...from the right-click menu, I get some generated code in my .h file:

    The problem you hit is that Visual Studio IDE does not honor calling convention of the existing interface declaration and generates code for default calling convention rather than __stdcall.

    So you are basically supposed to edit to STDMETHOD and you are good to go from there. And also hope that next Visual Studio will take calling convention into consideration in code generation and refactoring tools.

    The __stdcall calling convention is used to call Win32 API functions.

    Basically this calling convention is standard for all COM methods (often used through macros STDMETHOD, STDMETHOD_, STDMETHODCALLTYPE etc.), as well as other API declarations: CALLBACK, WINAPI resolve to __stdcall.

    MSDN should have been more clear about __stdcall and not assume that it goes without saying:

    ... Certain necessary calling convention details, such as __stdcall are left out for this illustration...

    And if you are in doubt regarding convention to use in communication with Windows API, start with __stdcall as it's your best bet.