Ответ 1
Если интерфейс правильно определен в IDL и скомпилирован в библиотеку типов, реализация IDispatch
через библиотеку типов ITypeInfo
вполне осуществима, поскольку она в основном делегирует. Интересная часть ITypeInfo::Invoke
, которая основывается на правильной компоновке V-таблицы С++:
public class CComClass: public IDualInterface
{
// ...
// implementing IDualInterface
ITypeInfo* m_pTypeInfo // can be obtained via ITypeLib::GetTypeInfoOfGuid for the GUID of IDualInterface
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
{
*pctinfo = 1;
return S_OK;
}
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
if (0 != itinfo)
return E_INVALIDARG;
(*pptinfo = m_pTypeInfo)->AddRef();
return S_OK;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
}
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return m_pTypeInfo->Invoke(static_cast<IDualInterface*>(this), dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
}
Я использовал аналогичный подход для создания a script -callable wrapper для объектов DOM MSHTML, чтобы обойти ограничения безопасности сценариев.
Итак, откуда вы получаете ITypeInfo? По существу вы получаете его:
- Напишите файл IDL, который объявит ваш интерфейс как dual. Это должен быть двойной интерфейс, так как реализация
ITypeInfo
знает, какую функцию вызывать - она не может просто вызвать функции С++ непосредственно на вашем классе, потому что С++ не имеет никакого отражения и потому что он является нейтральным языком. Поэтому он может делегировать вызовInvoke
другому методу, объявленному в библиотеке типов. - Скомпилируйте IDL в файл заголовка и введите библиотеку как часть процесса сборки
- Заголовочный файл, созданный из IDL, определяет интерфейс, на который должен наследоваться ваш класс реализации. После того, как вы внедрили все методы, вам хорошо идти. (Для разработки начинайте с того, что все они возвращаются
E_NOTIMPL
, затем реализуют их один за другим) - Установите библиотеку типов либо в целевой каталог, либо в качестве ресурса в EXE/DLL. Его нужно зарегистрировать, позвонив
RegisterTypeLib
. Если он встроен в качестве ресурса, вы должны вызвать его из своей реализацииDllRegisterServer
. - Загрузите библиотеку типов, когда создается первый экземпляр вашего объекта, используя
LoadTypeLib
. Это дает вамITypeLib
- Получите ITypeInfo, который вам нужен, используя
GetTypeInfoOfGuid
.