Directory Services

Supporting Dual or Dispatch Interfaces

Like the dispatch interface, all dual interfaces must inherit from IDispatch, which delegates all of its IDispatch functions (GetIDsOfNames, Invoke, GetTypeInfo, GetTypeInfoCount) back to the IDispatch of the aggregator (ADSI). To execute the delegation, an extension object should query for the IDispatch of the aggregator, call the appropriate aggregator method, and release the pointer after use.

If the extension can be a standalone component, verify that it is aggregated. If so, reroute the dispatch functions to the IDispatch of the aggregator, otherwise you can call your internal implementation of IDispatch, or you can call your implementation of IADsExtension.

The following code example shows how to reroute the IDispatch call to the IDispatch of the aggregator. This code example assumes that the m_pOuterUnknown member variable has been initialized to the IUnknown pointer of the aggregator.

[C++]
/////////////////////////////////////////////////// 
// 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;
}

Extension writers are strongly encouraged to support dual interfaces instead of dispatch interfaces in their extension objects. A dual interface enables a client to have faster access, as long as vtable access is enabled in the client. For more information, see Late Binding vs. Vtable Access in the ADSI Extension Model. Based on the current model, implementing dual interfaces should not be more difficult than implementing dispatch interfaces.