Поддержка двух или диспетчерских интерфейсов
Как и интерфейс отправки, все два интерфейса должны наследоваться от IDispatch, который делегирует все его функции IDispatch (GetIDsOfNames, Invoke, GetTypeInfo, GetTypeInfoCount) обратно в IDispatch агрегатора (ADSI). Чтобы делегировать, объект расширения должен запрашивать IDispatch агрегатора, вызывать соответствующий метод агрегатора и освобождать указатель после использования.
Если расширение может быть автономным компонентом, убедитесь, что оно агрегировано. В этом случае перенаправьте функции диспетчера в IDispatch агрегатора, в противном случае можно вызвать внутреннюю реализацию IDispatch или вызвать реализацию IADsExtension.
В следующем примере кода показано, как перенаправить вызов IDispatch в IDispatch агрегатора. В этом примере кода предполагается, что переменная элемента m_pOuterUnknown была инициализирована в указатель IUnknown агрегатора.
///////////////////////////////////////////////////
// Delegating IDispatch Methods to the aggregator
///////////////////////////////////////////////////
STDMETHODIMP MyExtension::GetTypeInfoCount(UINT* pctinfo)
{
IDispatch *pDisp = NULL;
HRESULT hr = S_OK;
hr = m_pOuterUnknown->QueryInterface( IID_IDispatch, (void**) &pDisp );
if ( SUCCEEDED(hr) )
{
hr = pDisp->GetTypeInfoCount( pctinfo );
pDisp->Release();
}
return hr;
}
STDMETHODIMP MyExtension::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
IDispatch *pDisp = NULL;
HRESULT hr = S_OK;
hr = m_pOuterUnknown->QueryInterface( IID_IDispatch, (void**) &pDisp );
if ( SUCCEEDED(hr) )
{
hr = pDisp->GetTypeInfo( itinfo, lcid, pptinfo );
pDisp->Release();
}
return hr;
}
STDMETHODIMP MyExtension::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
IDispatch *pDisp = NULL;
HRESULT hr = S_OK;
hr = m_pOuterUnknown->QueryInterface( IID_IDispatch, (void**) &pDisp );
if ( SUCCEEDED(hr) )
{
hr = pDisp->GetIDsOfNames( riid, rgszNames, cNames, lcid,
rgdispid);
pDisp->Release();
}
return hr;
}
STDMETHODIMP MyExtension::Invoke(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT*
pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
IDispatch *pDisp = NULL;
HRESULT hr = S_OK;
hr = m_pOuterUnknown->QueryInterface( IID_IDispatch, (void**) &pDisp );
if ( SUCCEEDED(hr) )
{
hr = pDisp->Invoke( dispidMember, riid, lcid, wFlags,
pdispparams, pvarResult, pexcepinfo, puArgErr);
pDisp->Release();
}
return hr;
}
Записи расширений настоятельно рекомендуется поддерживать двойные интерфейсы вместо интерфейсов диспетчеризации в своих объектах расширения. Двойной интерфейс позволяет клиенту быстрее получать доступ, если в клиенте включен доступ к vtable. Дополнительные сведения см. в разделе "Поздняя привязка" и "Vtable Access" в модели расширения ADSI. На основе текущей модели реализация двух интерфейсов не должна быть более сложной, чем реализация интерфейсов диспетчера.