Visual Studio - 为什么 MSDN 或 VS2015 不按照约定声明 IUnknown 方法__stdcall?



如果这个问题有点跑题,我道歉。我正在使用COM,在Windows 10下使用Visual Studio 2015社区编写一些简单的COM服务器和对象。所有COM对象都必须实现IUnknown接口。VS2015的IDE将提供实现超类的虚函数。因此,如果我创建example。h,包含以下内容:

#include <Unknwn.h>
class MyClass : public IUnknown
{
};

然后选择Quick Actions And Refactorings…/实现所有的纯虚拟类'MyClass ',从右键菜单,我得到一些生成的代码在我的。h文件:

#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;
};

VS2015还为我提供了一个存根实现:

#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;
}

这很好,但是不能编译。我得到这个错误信息:

错误C2695: 'CFactory3::QueryInterface':重写虚拟函数与'IUnknown::QueryInterface'不同,只是调用约定

我得到所有三个方法的错误消息。这是有意义的,因为每个方法的实际声明都指定了__stdcall调用约定。现在,我可以将它添加到MyClass的声明中,如下所示:

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

可以正常编译。

我知道要使用什么调用约定,因为,首先,当我使用"Peek Definition"时,我看到如下:

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

再深入一层,我看到STDMETHODCALLTYPE只是一个定义为__stdcall的宏。其次,我的大多数教程材料都建议使用STDMETHODIMP宏(扩展到HRESULT STDMETHODCALLTYPE)实现IUnknown方法。

然而,当我查看关于IUnknown方法的MSDN页面时,没有提到需要任何特定的调用约定。

所以我想知道为什么在MSDN页面上没有提到IUnknown方法的__stdcall约定,以及为什么VS2015 IDE没有将它包含在我的子类的IUnknown的存根实现中。

一般来说,如何查找一个方法或函数的必要调用约定,该方法或函数将由COM调用,或由Windows的任何其他部分调用?

从右键菜单,我得到一些生成的代码在我的。h文件:

你遇到的问题是Visual Studio IDE不尊重现有接口声明的调用约定,并为默认调用约定而不是__stdcall生成代码。

所以你基本上应该编辑到STDMETHOD,你很好从那里去。同时也希望下一个Visual Studio能够在代码生成和重构工具中考虑调用约定。

使用__stdcall调用约定调用Win32 API函数。

基本上,这个调用约定是所有COM方法的标准(通常通过宏STDMETHOD, STDMETHOD_, STDMETHODCALLTYPE等使用),以及其他API声明:CALLBACK, WINAPI解析为__stdcall

MSDN应该更清楚地说明__stdcall,而不是假设它没有说明:

…某些必要的调用约定细节,例如__stdcall,在此示例中被省略了…

如果你对使用Windows API通信的约定有疑问,从__stdcall开始,因为它是你最好的选择。

最新更新