Figure 2   AppWizard-generated ODL


 // DualCtl.odl : type library source for OLE Control project.
 
 #include <olectl.h>
 #include <idispids.h>
 
 [ uuid(6E281361-40AF-11D0-8A90-E1C000C3FC20), 
   version(1.0),
   helpstring("DualCtl OLE Control module"), 
   control ]
 library DUALCTLLib
 {
    importlib(STDOLE_TLB);
    importlib(STDTYPE_TLB);
 
    //  Primary dispatch interface for CDualCtlCtrl
    [ uuid(6E281362-40AF-11D0-8A90-E1C000C3FC20),
      helpstring("Dispatch interface for DualCtl Control"),
      hidden ]
    dispinterface _DDualCtl {
       properties:
          // ClassWizard Voodoo warnings
         [id(3)] long AProperty;
         [id(2)] float NotificationProperty;
         [id(1)] double PlainVanillaProperty;
 
       methods:
         [id(4)] short AFunction(short Param1);
         [id(DISPID_ABOUTBOX)] void AboutBox();
    };
 
    //  Event dispatch interface for CDualCtlCtrl
    [uuid(6E281363-40AF-11D0-8A90-E1C000C3FC20),
       helpstring("Event interface for DualCtl Control") ]
       dispinterface _DDualCtlEvents
    {
       properties:
          //  Event interface has no properties
 
       methods:
 };
 
    //  Class information for CDualCtlCtrl
    [uuid(6E281364-40AF-11D0-8A90-E1C000C3FC20),
     helpstring("DualCtl Control"), 
     control 
    ]
    coclass DualCtl {
       [default] dispinterface _DDualCtl;
       [default, source] dispinterface _DDualCtlEvents;
    };
 };

Figure 3   The Dual Interface Described in ODL


    [uuid(49BA7C01-40D4-11d0-8A90-E1C000C3FC20),
     helpstring("Dual interface for DualCtl Control"), 
     dual,
     oleautomationp 
    ]
    interface _DIDualCtl : IDispatch {
          [propput, id(3)] HRESULT AProperty([in] long l);
          [propget, id(3)] HRESULT AProperty([retval, out] long* pl);
          [propput, id(1)] HRESULT PlainVanillaProperty([in] double d);
          [propget, id(1)] HRESULT PlainVanillaProperty([retval, 
                                                        out] double* pd);
          [propput, id(2)] HRESULT NotificationProperty([in]float f);
          [propget, id(2)] HRESULT NotificationProperty([retval, 
                                                        out] float* pf);
          [id(4)] HRESULT AFunction([in] short Param1, [out, retval] short *s);
          [id(DISPID_ABOUTBOX)] HRESULT AboutBox();
   };

Figure 4   MKTYPLIB Emits this Header File


 DEFINE_GUID(IID__DIDualCtl,0x49BA7C01L,0x40D4,0x11D0,0x8A,0x90,0xE1,0xC0,0x00,
             0xC3,0xFC,0x20);
 
 /* Definition of interface: _DIDualCtl */
 #undef INTERFACE
 #define INTERFACE _DIDualCtl
 
 DECLARE_INTERFACE_(_DIDualCtl, IDispatch)
 {
 #ifndef NO_BASEINTERFACE_FUNCS
 
     /* IUnknown methods */
     STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
     STDMETHOD_(ULONG, AddRef)(THIS) PURE;
     STDMETHOD_(ULONG, Release)(THIS) PURE;
 
     /* IDispatch methods */
     STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;
 
     STDMETHOD(GetTypeInfo)(
       THIS_
       UINT itinfo,
       LCID lcid,
       ITypeInfo FAR* FAR* pptinfo) PURE;
 
     STDMETHOD(GetIDsOfNames)(
       THIS_
       REFIID riid,
       OLECHAR FAR* FAR* rgszNames,
       UINT cNames,
       LCID lcid,
       DISPID FAR* rgdispid) PURE;
 
     STDMETHOD(Invoke)(
       THIS_
       DISPID dispidMember,
       REFIID riid,
       LCID lcid,
       WORD wFlags,
       DISPPARAMS FAR* pdispparams,
       VARIANT FAR* pvarResult,
       EXCEPINFO FAR* pexcepinfo,
       UINT FAR* puArgErr) PURE;
 #endif
 
     /* _DIDualCtl methods */
     STDMETHOD(put_AProperty)(THIS_ long l) PURE;
     STDMETHOD(get_AProperty)(THIS_ long FAR* pl) PURE;
     STDMETHOD(put_PlainVanillaProperty)(THIS_ double d) PURE;
     STDMETHOD(get_PlainVanillaProperty)(THIS_ double FAR* pd) PURE;
     STDMETHOD(put_NotificationProperty)(THIS_ float f) PURE;
     STDMETHOD(get_NotificationProperty)(THIS_ float FAR* pf) PURE;
     STDMETHOD(AFunction)(THIS_ short Param1, short FAR* s) PURE;
     STDMETHOD(AboutBox)(THIS) PURE;
};

Figure 5   Declaring the Nested Class


 // Inside the control's header file-- the control's declaration
 class CDualCtlCtrl : public COleCtontrol {
 .
 .
 .
 BEGIN_DUAL_INTERFACE_PART(_DIDualCtlObj, _DIDualCtl)
        STDMETHOD(put_AProperty)(long l);
        STDMETHOD(get_AProperty)(long FAR* pl);
        STDMETHOD(put_PlainVanillaProperty)(double d);
        STDMETHOD(get_PlainVanillaProperty)(double FAR* pd);
        STDMETHOD(put_NotificationProperty)(float f);
        STDMETHOD(get_NotificationProperty)(float FAR* pf);
        STDMETHOD(AFunction)(short Param1, short FAR* s);
        STDMETHOD(AboutBox)();
 END_DUAL_INTERFACE_PART(_DIDualCtlObj)
 .
 .
 .
 };

Figure 6   Implementing IUnknown and IDispatch


 STDMETHODIMP 
    CDualCtlCtrl::X_DIDualCtlObj::QueryInterface(REFIID riid, 
                                                 LPVOID FAR* ppvObj) {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     return pThis->ExternalQueryInterface(&riid, ppvObj);
 }
 
 STDMETHODIMP_(ULONG) 
    CDualCtlCtrl::X_DIDualCtlObj::AddRef() {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     return pThis->ExternalAddRef();
 }
 
 STDMETHODIMP_(ULONG) 
    CDualCtlCtrl::X_DIDualCtlObj::Release() {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     return pThis->ExternalRelease();
 }
 STDMETHODIMP 
    CDualCtlCtrl::X_DIDualCtlObj::GetTypeInfoCount(UINT FAR* pctinfo) {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     LPDISPATCH pDisp = pThis->GetIDispatch(FALSE);
     ASSERT(pDisp != NULL);
     return pDisp->GetTypeInfoCount(pctinfo);
 }
 
 STDMETHODIMP 
    CDualCtlCtrl::X_DIDualCtlObj::GetTypeInfo(UINT itinfo,
                                              LCID lcid,
                                              ITypeInfo FAR* FAR* pptinfo) {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     LPDISPATCH pDisp = pThis->GetIDispatch(FALSE);
     ASSERT(pDisp != NULL);
     return pDisp->GetTypeInfo(itinfo, lcid, pptinfo);
 }
 
 STDMETHODIMP 
    CDualCtlCtrl::X_DIDualCtlObj::GetIDsOfNames(REFIID riid,
                                OLECHAR FAR* FAR* rgszNames,
                                UINT cNames,
                                LCID lcid,
                                DISPID FAR* rgdispid) {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     LPDISPATCH pDisp = pThis->GetIDispatch(FALSE);
     ASSERT(pDisp != NULL);
     return pDisp->GetIDsOfNames(riid, rgszNames,
                                 cNames,lcid, 
                                 rgdispid);
 }
 
 STDMETHODIMP 
    CDualCtlCtrl::X_DIDualCtlObj::Invoke(DISPID dispidMember,
                                         REFIID riid,
                                         LCID lcid,
                                         WORD wFlags,
                                         DISPPARAMS FAR* pdispparams,
                                         VARIANT FAR* pvarResult,
                                         EXCEPINFO FAR* pexcepinfo,
                                         UINT FAR* puArgErr) {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
     LPDISPATCH pDisp = pThis->GetIDispatch(FALSE);
     ASSERT(pDisp != NULL);
     return pDisp->Invoke(dispidMember,
                          riid,
                          lcid,
                          wFlags,
                          pdispparams,
                          pvarResult,
                          pexcepinfo,
                          puArgErr);
 }

Figure 7   Implementing the Rest of the Function and Property Accessors


 STDMETHODIMP CDualCtlCtrl::X_DIDualCtlObj::put_AProperty(long l) {
    METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
    pThis->SetAProperty(l);
    return NOERROR;
 }
 
 STDMETHODIMP CDualCtlCtrl::X_DIDualCtlObj::get_AProperty(long FAR* pl) {
    METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
    *pl = pThis->GetAProperty();
    return NOERROR;
 }
 
 STDMETHODIMP CDualCtlCtrl::X_DIDualCtlObj::AFunction(short Param1, 
                                                      short FAR* s) {
     METHOD_PROLOGUE(CDualCtlCtrl, _DIDualCtlObj)
         *s = pThis->AFunction(Param1);
         return NOERROR;
 }