Because there are three ways of defining a dispatch-based interface, this sample also provides dispimpl2.h, a header file that provides three C++ classes, one for each method of defining a dispatch interface.
[dual] interface IFoo : IDispatch { HRESULT DoFoo(); }Implementing the IDispatch portion of a dual interface is usually managed using a typeinfo object. Given a typeinfo, all four methods of IDispatch are one liners, mostly letter the typeinfo object do the work.
ATL's IDispatchImpl requires dispatch-based interfaces to be defined as dual interfaces.
[oleautomation] interface IFoo : IUnknown { HRESULT DoFoo(); } dispinterface DFoo { interface IFoo; // Logically delegate to another interface }Implementing DFoo is a matter of loading a typeinfo and having it forward to methods of IFoo (as this definition promises). Again, given a typeinfo object, the implementation of this kind of dispatch-based interface is easy.
Unfortunately, the implementation is different enough (the object must derive from both DFoo and IFoo), that IDispatchImpl doesn't do the trick. However, since the majority of the implementation of IDispatchImpl lies in CComTypeInfoHolder, a small class defined for delegating dispinterfaces could easily do the job. The dispimpl2.h header file provides such a class (IDelegatingDispImpl).
dispinterface DFoo { properties: BSTR Foo; methods: void DoFoo(); }Notice that no real interface is involved. DFoo will be generated in IDL as an interface that derives from IDispatch and provides no additional methods. However, a typeinfo object is still useful for implementing three out of four of the IDispatch member functions. However, Invoke is left up to the implementor. Yet another C++ class can be defined that does 3/4th of the work, leaving Invoke to the implementor. The dispimpl2.h header file provides such a class (IRawDispImpl).
class CFoo : ..., public IDualDispImpl<IFoo> { ... BEGIN_COM_MAP(CFoo) COM_INTERFACE_ENTRY(IFoo) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() ... };Of course, the custom methods of IFoo are up to the implementor as well.
class CFoo : ..., public IDelegatingDispImpl<DFoo, IFoo> { ... BEGIN_COM_MAP(CFoo) COM_INTERFACE_ENTRY(IFoo) COM_INTERFACE_ENTRY(DFoo) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() ... };Again, the implementor is responsible for all of the custom IFoo methods.
class CFoo : ..., public IRawDispImpl<DFoo> { ... BEGIN_COM_MAP(CFoo) COM_INTERFACE_ENTRY(DFoo) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() ... STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr); };Responsible C++ programmers will implement Invoke to validate, convert and forward arguments to a real member function, as the typeinfo object does in the case of the other two types of interfaces.
Contact the author with suggestions or comments at csells@sellsbrothers.com.