Multiple Dispatch Interfaces in ATL | CodeGuru

Multiple Dispatch Interfaces in ATL

Most of COM objects implement more than one interface. These interfaces are usually dual interfaces, which means they implement IDispatch as well. If you use such an object from a programming environment that can access IUnknown, all the interfaces are available through the QueryInterface method.  Using the object from scripting (automation) environments (like VBScript) leave […]

Written By
CodeGuru Staff
CodeGuru Staff
Jun 25, 1999
3 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Most of COM objects implement more than one interface. These interfaces are usually
dual interfaces, which means they implement IDispatch as well. If you use such an object
from a programming environment that can access IUnknown, all the interfaces are available
through the QueryInterface method.  Using the object from scripting (automation)
environments (like VBScript) leave you with only one interface – IDispatch.

Consider the following example:

Let’s say that there are two interfaces, IFly and IWalk,
that you want to implement in your object Bird. Both interfaces are
defined as dual, so each of them has an IDispatch interface. Your object Bird implements
the interfaces, but also have to expose IDispatch interface in order to allow it to be
accessed by an automation environment. Since only one IDispatch is allowed (using
QueryInterface with IDispatch should always returns the same interface), you have
couple of  options:

  • Chose one of the interfaces (IFly or IWalk) and use its IDispatch as the IDispatch
    exposed by Bird. This is the default option for an ATL object. If you
    have more than one interface derived from IDispatch, you have to specify each one should
    be used for IDispatch with the macro COM_INTERFACE_ENTRY2(IDispatch, yourInterface).
    This approach leaves parts of your object inaccessible from automation.
  • Design a new IDispatch that implements all the functionality from both interfaces.
    Drawback: adds a lot of complexity ( multiple interfaces to be delegated, big number of
    properties and methods) and more work for each object( you have to design new interfaces).
  • Create methods in your interfaces that give access to other interfaces.
    That reduces the reusability of your interfaces. It also violates the
    symmetric and transitive principles, since the methods will return
    interfaces to the same object.

The Solution

The goal is to find a legitimate way to identify different IDispatch implementations and
ability to access them from automation environments.
The solutions is to add a new method to each IDispatch (but not to the interface itself),
called QueryDispatch. It will provide navigation between the different
IDispatches. The implementation should act like QueryInterface ; i.e. be reflexive,
symmetric, and transitive.

Property Meaning
Reflexive pIOne->QueryInterface(IID_IOne) must succeed.

 

Symmetric If pITwo was obtained from pIOne->QueryInterface(IID_ITwo),
then pITwo->QueryInterface(IID_IOne) must also succeed.

 

Transitive If pITwo was obtained from pIOne->QueryInterface(IID_ITwo)
and pIThree was obtained from pITwo->QueryInterface(IID_IThree), then pIThree->QueryInterface(IID_IOne)
must also succeed.

The IDL definition is:

[propget, id(IDQUERYDISPATCH)]
HRESULT QueryDispatch([in] BSTR dispName,[out, retval] VARIANT* pVal);

In ATL  the dispatch part of a dual interface
is implemented automatically. All you have to do is provide access to it. This
is done by modifying the IDispatchImpl. The new method (QueryDispatch) is
implemented by default.

The Implementation

The system files that you need are:

QueryDispatch.h – header file with macros for ATL

Implement your dual interfaces as usual. Substitute IDispatchImpl
with IDQDispatchImpl,  add
BEGIN_QUERYDISPATCH_MAP and
you are done.

#include " QueryDispatch"
class ATL_NO_VTABLE CQryDispObj :
	   public CComObjectRootEx<CComSingleThreadModel>,
	   public CComCoClass<CQryDispObj, &CLSID_QryDispObj>,
	   public IQDDispatchImpl<CQryDispObj,  IQryDispObj,  &IID_IQryDispObj,  &LIBID_QUERYDISPATCHTESTLib>,
	   public IQDDispatchImpl<CQryDispObj,  IWalk,   &IID_IWalk,   &LIBID_QUERYDISPATCHTESTLib>
{
    // Specify that IQDDispatchImpl interface will be used    as default IDispatch for the object
    BEGIN_COM_MAP(CQryDispObj)
     COM_INTERFACE_ENTRY2(IDispatch,IQryDispObj)
     COM_INTERFACE_ENTRY(IQryDispObj)
     COM_INTERFACE_ENTRY(IWalk)
    END_COM_MAP()
    // Declare all dual interfaces that will be   supported. The names are the name of the interface (without the IID_ part).
    BEGIN_QUERYDISPATCH_MAP
     QDDISPATCH_ENTRY(IQryDispObj)
     QDDISPATCH_ENTRY(IWalk)
    END_QUERYDISPATCH_MAP
};
Advertisement

The Scripting Environment

For each object which implements multiple IDispatches and each IDispatch must include
QueryDispatch. To use any dual interface of the object, you need to obtain the IDispatch
for the object , query for the desired interface and use it as usual. Here is example for
VBScript:

create the object as usual
	Dim server
	Set server = CreateObject("vp.QryDispObj")
	‘query for the IWalk dispatch interface
	Dim dispWalk
	set dispWalk = server.QueryDispatch(“IWalk”)
	‘use the interface as usual
	dispWalk.Walk = “walk”
  

Download demo project – 11 KB

Download source – 3 KB

History

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.