Легко реализовать интерфейс только для IDispatch на C++C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Легко реализовать интерфейс только для IDispatch на C++

Сообщение Anonymous »

В моем проекте C# я определил следующий интерфейс только для IDispatch:

Код: Выделить всё

    [ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("3532C4E8-D320-487C-8BD4-F448B94B9E83")]
public interface ICppRuntimeApi2
{
[DispId(1)]
bool TestCallback(string pasteType);
}
После импорта созданной библиотеки типов в мой проект C++ я могу свободно реализовать свой ICppRuntimeApi2, как, например:

Код: Выделить всё

class CppRuntimeApiImpl2 : public MyProject::ICppRuntimeApi2 {
public:
CppRuntimeApiImpl2() : refCount(1) {}

// IUnknown methods
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv) override {
if (riid == IID_IUnknown || riid == IID_IDispatch || riid == __uuidof(MyProject::ICppRuntimeApi2)) {
*ppv = static_cast(this);
}
else {
*ppv = nullptr;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}

ULONG __stdcall AddRef() override {
return InterlockedIncrement(&refCount);
}

ULONG __stdcall Release() override {
ULONG count = InterlockedDecrement(&refCount);
if (count == 0) {
delete this;
}
return count;
}

// IDispatch methods
HRESULT __stdcall GetTypeInfoCount(UINT* pctinfo) override {
*pctinfo = 0;
return S_OK;
}

HRESULT __stdcall GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override {
*ppTInfo = nullptr;
return E_NOTIMPL;
}

HRESULT __stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override {
if (cNames != 1) return DISP_E_UNKNOWNNAME;
if (_wcsicmp(rgszNames[0], L"TestCallback") == 0) {
rgDispId[0] = 1;
return S_OK;
}
return DISP_E_UNKNOWNNAME;
}

HRESULT __stdcall Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override {
if (dispIdMember == 1) {
if (pDispParams->cArgs != 1 || pDispParams->rgvarg[0].vt != VT_BSTR) {
return DISP_E_BADPARAMCOUNT;
}
std::wstring pasteType(pDispParams->rgvarg[0].bstrVal, SysStringLen(pDispParams->rgvarg[0].bstrVal));
bool result = TestCallback(pasteType);
if (pVarResult) {
pVarResult->vt = VT_BOOL;
pVarResult->boolVal = result ? VARIANT_TRUE : VARIANT_FALSE;
}
return S_OK;
}
return DISP_E_MEMBERNOTFOUND;
}

// ICppRuntimeApi2 method
bool TestCallback(const std::wstring& pasteType) {
MessageBoxW(nullptr, (L"TestCallback call via COM interop! \nTag: " + pasteType).c_str(), L"TestCallback", MB_OK);
return true;
}

private:
LONG refCount;
};

Это решение работает, но очевидно, что это нежизнеспособное решение. Для новых методов потребуются значительные ручные усилия для реализации каждой проверки DispID, проверки типа параметров и вызова реальной логической стороны C++.
Позже я обнаружил, что с помощью ATL можно реализовать класс IDispEventImpl, а затем использовать макросы SINK_ENTRY для «регистрации» методов без ввода проверок вручную, но я не могу заставить его работать. Вызов метода TestCallback из C#, похоже, ничего не вызывает. Я пытался вызвать функции Advise, но все равно не работает.
В любом случае, чтобы достичь хотя бы этого момента, ATL потребовалась инициализация модуля и множество шаблонного кода, который, я думаю, немного излишен для моих нужд.
Существует ли более легкое решение, кроме использования ATL, для реализации интерфейса только для IDispatch на C++, но более «автоматическим» и менее ручным способом?

Подробнее здесь: https://stackoverflow.com/questions/796 ... asily-in-c
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»