Undocumented Corner
by George Shepherd and Scot Wingo


Listing One
struct ISomeInterface : public IUnknown {
   HRESULT SomeFunction();
   HRESULT AnotherFunction();
};

Listing Two
void UseSomeInterface(ISomeInterface* pSomeInterface) {
   pSomeInterface->SomeFunction();
   pSomeInterface->AnotherFunction();
}

Listing Three
interface IDispatch : public IUnknown {
   HRESULT GetTypeInfoCount(UINT FAR* pctinfo);
   HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
   HRESULT GetIDsOfNames(REFIID riid, char FAR* FAR* rgszNames,
                         UINT cNames, LCID lcid, DISPID FAR* rgdispid);
   HRESULT Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
                  WORD wFlags, DISPPARAMS FAR* pdispparams,
                  VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo,
                  UINT FAR* puArgErr);
};


Listing Four
interface ISomeDualInterface : public IDispatch {
   virtual void HRESULT Function1();
   virtual void HRESULT Function2();
   virtual void HRESULT Function3();
};

Listing Five
[
   object,
   uuid(271165EE-2110-11D1-8CAA-FD10872CC837),
   dual
]
interface IDualTestOb : IDispatch
{
   [id(1)] HRESULT Function1();
   [id(2)] HRESULT Function2();
   [id(3)] HRESULT Function3();s
};

Listing Six
class CSomeObject : public ISomeDualInterface {
  ITypeInfo *m_pTypeInfo;
public:
  CSomeObject(void) : m_pTypeInfo(0) {  
    ITypeLib *ptl = 0;
    if (SUCCEEDED(LoadTypeLib(g_wszTypeLib, &ptl))) {
      ptl->GetTypeInfoOfGuid(IID_ISomeDualInterface, &m_pTypeInfo);  
      ptl->Release();}
  }
  HRESULT QueryInterface(REFIID riid, void **ppv) {
    if (riid == IID_ISomeDualInterface) 
      *ppv = m_pTypeInfo ? (ISomeDualInterface*) this : 0;
    else if (riid == IID_IDispatch) 
      *ppv = m_pTypeInfo ? (DIFoo*) this : 0;
    else if (riid == IID_IUnknown) 
      *ppv = (DIFoo*) this;
    else *ppv = 0;
     :
  }
  HRESULT GetTypeInfoCount(UINT * pticount) 
  {
    *pticount = 1;
    return NOERROR;
  }
  HRESULT GetTypeInfo(UINT i, LCID lcid, ITypeInfo**ppti)
  {
    if (i != 0) return DISP_E_BADINDEX;
    (*ppti = m_pTypeInfo)->AddRef();
    return NOERROR;
  }
  HRESULT Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags,  
                 DISPPARAMS * pdispparams, VARIANT * pvarResult, 
                 EXCEPINFO * pei, UINT * puArgErr) {
    return m_pTypeInfo->Invoke((ISomeDualInterface*)this, dispid, wFlags, 
                                 pdispparams, pvarResult, pei, puArgErr);
  }  
  HRESULT GetIDsOfNames(REFIID riid, OLECHAR* rgszNames[],
                        UINT cNames, LCID lcid, DISPID rgdispid[]) {
   return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  }
   ...
// Implement the rest of IUnknown and the dual interface functions...


Listing Seven
class ATL_NO_VTABLE CDualTestOb : 
  public CComObjectRootEx<CComSingleThreadModel>,
  public CComCoClass<CDualTestOb, &CLSID_DualTestOb>,
  public IDispatchImpl<ISomeDualInterface, &IID_ISomeDualInterface, 
                       &LIBID_DUALTESTLib> {
};


Listing Eight
BEGIN_COM_MAP(CDualTestOb)
   COM_INTERFACE_ENTRY(ISomeDualInterface)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()


Listing Nine
class ATL_NO_VTABLE CDualTestOb : 
  public CComObjectRootEx<CComSingleThreadModel>,
  public CComCoClass<CDualTestOb, &CLSID_DualTestOb>,
  public IDispatchImpl<ISomeDualInterface, &IID_ISomeDualInterface, 
                       &LIBID_DUALTESTLib> 
  public IDispatchImpl<IAnotherDualInterface, &IID_IAnotherDualInterface, 
                       &LIBID_DUALTESTLib> {
};

Listing Ten
BEGIN_COM_MAP(CDualTestOb)
   COM_INTERFACE_ENTRY(ISomeDualInterface)
   COM_INTERFACE_ENTRY(IAnotherDualInterface)
   COM_INTERFACE_ENTRY2(IDispatch, ISomeDualInterface)
END_COM_MAP()

1


