Figure 4   IMPLEMENT_IUnknownCT


 ////////////////////////////////////////////////////////////////
 // Macro expansion for IMPLEMENT_IUnknownCT(CMyComClass)
 
 STDMETHODIMP_(ULONG) CMyComClass::AddRef()
 {
    CMDTARGENTRYTR(_T("CMyComClass(%p)::AddRef "),this);
    DWORD dwRef = ExternalAddRef();
    CTTRACE(_T("> returns count=%d\n"),dwRef);
    return dwRef;
 }
 
 STDMETHODIMP_(ULONG) CMyComClass::Release()
 {
    CMDTARGENTRYTR(_T("CMyComClass(%p)::Release "),this);
    DWORD dwRef = ExternalRelease();
    CTTRACE(_T("> returns count=%d\n"),dwRef);
    return dwRef;
 }
 
 STDMETHODIMP CMyComClass::QueryInterface(REFIID iid, LPVOID* ppvRet)
 {
    CTCHECKARG(ppvRet);
    CMDTARGENTRYTR(_T("CMyComClass(%p)::QueryInterface(%s) "), this, _TR(iid));
    HRESULT hr = ExternalQueryInterface(&iid, ppvRet);
    CTTRACE(_T("> returns %s, *ppv=%p, count=%d\n"),
       _TR(hr), *ppvRet, CCmdTarget::m_dwRef);
    return hr;
 }
 
 // Expansion of CMDTARGENTRYTR.
 // NOTE: when you create a CCmdTarget object, MFC initializes
 // m_pModuleState = AfxGetModuleState();
 //
    AFX_MANAGE_STATE(m_pModuleState);
    TRACE(...);

Figure 5   CBandObj


 //////////////////
 // CBandObj -- A typical COM class that implements several interfaces.
 
 // in .h file:
 class CBandObj : public CWnd,
 
    // interfaces 
 // public IOleWindow,      // inherited from IDeskBand
 // public IDockingWindow,  // inherited from IDeskBand
    public IDeskBand,
    public IObjectWithSite,
    public IInputObject,
 // public IPersist,        // inherited from IPersistStream
    public IPersistStream,
    public IContextMenu,
 
    // implementations using ComToys
    public CTOleWindow,
    public CTDockingWindow,
    public CTPersist,
    public CTPersistStream,
    public CTInputObject,
    public CTInputObjectSite,
    public CTContextMenu
 {
 public:
    CBandObj(REFCLSID clsid);
    virtual ~CBandObj();
 
    // override to implement QueryInterface
    virtual LPUNKNOWN GetInterfaceHook(const void* iid);
 
    // interfaces implemented using ComToys
    DECLARE_IUnknown();
    DECLARE_IOleWindow();
    DECLARE_IDockingWindow();
    DECLARE_IInputObject();
    DECLARE_IPersist();
    DECLARE_IPersistStream();
    DECLARE_IContextMenu();
    DECLARE_IObjectWithSite();
 
    // IDeskBand
    STDMETHOD (GetBandInfo) (DWORD, DWORD, DESKBANDINFO*);
 };
 
 // in .cpp file:
 CBandObj::CBandObj(REFCLSID clsid) :
    // initialize all the implementation classes
    CTMfcComObj(this),
    CTOleWindow(this),
    CTDockingWindow(this),
    CTPersist(clsid),
    CTPersistStream(),
    CTInputObject(this),
    CTContextMenu(this, CTMfcComObjFactory::GetFactory(clsid)->GetResourceID())
 {
 .
 .
 .
 }
 
 /////////////////
 // These macros implement all the interfaces using the ComToys
 //
 IMPLEMENT_IUnknown         (CBandObj, CTMfcComObj);
 IMPLEMENT_IOleWindow       (CBandObj, CTOleWindow);
 IMPLEMENT_IDockingWindow   (CBandObj, CTDockingWindow);
 IMPLEMENT_IPersist         (CBandObj, CTPersist);
 IMPLEMENT_IContextMenu     (CBandObj, CTContextMenu);
 IMPLEMENT_IPersistStream   (CBandObj, CTPersistStream);
 IMPLEMENT_IInputObject     (CBandObj, CTInputObject);
 
 //////////////////
 // This CCmdTarget override is used to bypass MFC's interface
 // maps in CCmdTarget::InternalQueryInterface.
 //
 LPUNKNOWN CBandObj::GetInterfaceHook(const void* piid)
 {
    REFIID iid = *((IID*)piid);
    if (iid==IID_IUnknown) 
       return (IDeskBand*)this;
 
 #define IF_INTERFACE(iid, iface)                            \
    if (iid==IID_##iface)                                    \
       return (iface*)this;                                  \
 
    IF_INTERFACE(iid, IOleWindow);
    IF_INTERFACE(iid, IDockingWindow);
    IF_INTERFACE(iid, IObjectWithSite);
    IF_INTERFACE(iid, IInputObject);
    IF_INTERFACE(iid, IPersist);
    IF_INTERFACE(iid, IPersistStream);
    IF_INTERFACE(iid, IContextMenu);
    IF_INTERFACE(iid, IDeskBand);
 
    return NULL;
 }

Figure 8   Registrar Variables


Registrar variables automatically defined by ComToys 
(CTComObjFactory::OnInitRegistryVariables)

%CLSID%          = class ID (GUID) (COleObjectFactory::m_clsid)
%MODULE%         = full pathname of DLL
%Title%          = title (resource substring 0)
%ClassName%      = human-readable COM class name (resource substring 1)
%ProgID%         = ProgID (resource substring 2)
%ThreadingModel% = "", "Apartment", "Free", or "Both" (m_nThreadingModel)

Figure 10   The Simplicity of Smart Pointers


 //////////////////
 // Typical COM function implemented WITHOUT smart pointers. This is even
 // worse when there are many exit paths.
 //
 STDMETHODIMP CExplorerBar::SetSite(IUnknown* punkSite)
 {
    // If a site is being held, release it.
    if(m_pSite) {
       m_pSite->Release();
       m_pSite = NULL;
    }
    // If punkSite is not NULL, a new site is being set.
    if (punkSite) {
 •
 •
 •
      // Get and keep the IInputObjectSite pointer.
       if (SUCCEEDED(punkSite->QueryInterface(IID_IInputObjectSite,
          (LPVOID*)&m_pSite))) {
          return S_OK;
       }  
       return E_FAIL;
    }
    return S_OK;
 }
 
 //////////////////
 // Same COM function implemented WITH smart pointers. 12 lines reduced to 2.
 // Because m_pSite is declared as CComQIPtr<IInputObjectSite>, there's no
 // need to call QueryInterface(IID_IInputObjectSite), nor any need to AddRef
 // the new pointer or Release the old one. The smart pointer takes care of
 // everything.
 //
 STDMETHODIMP CBandObj::SetSite(IUnknown* punkSite)
 {
    if (m_pSite = punkSite) {
 .
 .
 .
   }
    return punkSite && !m_pSite ? E_FAIL : S_OK;
 }