Compatibilidad con interfaces duales o de distribución

Al igual que la interfaz de distribución, todas las interfaces duales deben heredar de IDispatch, que delegue todas sus funciones IDispatch (GetIDsOfNames, Invoke, GetTypeInfo, GetTypeInfoCount) a la IDispatch del agregador (ADSI). Para delegar, un objeto de extensión debe consultar el IDispatch del agregador, llamar al método agregador adecuado y liberar el puntero después de su uso.

Si la extensión puede ser un componente independiente, compruebe que se agrega. Si es así, vuelva a enrutar las funciones de envío al IDispatch del agregador; de lo contrario, puede llamar a la implementación interna de IDispatch o puede llamar a la implementación de IADsExtension.

En el ejemplo de código siguiente se muestra cómo volver a enrutar la llamada IDispatch a IDispatch del agregador. En este ejemplo de código se supone que la variable miembro m_pOuterUnknown se ha inicializado en el puntero IUnknown del agregador.

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

Se recomienda encarecidamente que los escritores de extensiones admitan interfaces duales en lugar de interfaces de envío en sus objetos de extensión. Una interfaz dual permite a un cliente tener un acceso más rápido, siempre y cuando el acceso a vtable esté habilitado en el cliente. Para obtener más información, vea Enlace en tiempo de ejecución frente a acceso vtable en el modelo de extensión ADSI. En función del modelo actual, la implementación de interfaces duales no debe ser más difícil que la implementación de interfaces de distribución.