Почему MSDN или VS2015 не объявляют методы IUnknown с соглашением __stdcall?
Извиняюсь, если этот вопрос немного не сфокусирован. Я работаю с COM, пишу несколько простых COM-серверов и объектов для сообщества Visual Studio 2015 под Windows 10. Все COM-объекты должны реализовывать интерфейс IUnknown. IDE VS2015 предложит реализовать виртуальные функции суперкласса. Итак, если я создаю "Example.h" с этим содержанием:
#include <Unknwn.h>
class MyClass : public IUnknown
{
};
А затем я выбираю Быстрые действия и рефакторинги.../ Внедряю все Pure Virtuals для класса "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
, Во-вторых, большая часть учебного материала, который я имею, рекомендует, чтобы методы IUnknown были реализованы с STDMETHODIMP
макрос (который расширяется до HRESULT STDMETHODCALLTYPE
).
Однако, когда я смотрю на страницу MSDN, посвященную методам IUnknown, не упоминается о необходимости какого-либо конкретного соглашения о вызовах.
Так что мне интересно, почему __stdcall
соглашение не упомянуто на страницах MSDN для методов IUnknown, и почему IDE VS2015 не включил его в свои реализации заглушки IUnknown для моего подкласса.
В общем, как найти необходимое соглашение о вызовах для метода или функции, которые будут вызываться COM или любой другой частью Windows?
1 ответ
... из контекстного меню я получаю сгенерированный код в моем.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
как это ваша лучшая ставка.