Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an ATL COM class derived from a base class?

The "ATL simple object" wizard doesn't provide a way to specify that a new class is derived from an existing coclass and its interface. In Visual Studio 2008, how do I make a new ATL COM class derived from an existing one (i.e. Base implements IBase, and I want to make a new Derived class derived from Base that implements IDerived, where IDerived is derived from IBase.)

Update: it sounds simple, but a wizard-generated ATL class has up to six base classes, a COM map and a connection point map. Which of these base classes and maps should be repeated in the derived class? If maps are repeated in the derived class should they contain the contents of the base class map or just the additional items? Does the order of base classes matter? What about FinalConstruct() and FinalRelease()? Should DECLARE_PROTECT_FINAL_CONSTRUCT and DECLARE_REGISTRY_RESOURCEID be repeated in the derived class?

Here's a sample base class that is empty except for all the boilerplate. Now what should the derived class look like?

class ATL_NO_VTABLE CBase :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CBase, &CLSID_Base>,
    public ISupportErrorInfo,
    public IConnectionPointContainerImpl<CBase>,
    public CProxy_IBaseEvents<CBase>,
    public IDispatchImpl<IBase, &IID_IBase, &LIBID_ExampleLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
    CBase()
    {
    }

DECLARE_REGISTRY_RESOURCEID(IDR_Base)


BEGIN_COM_MAP(CBase)
    COM_INTERFACE_ENTRY(IBase)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(ISupportErrorInfo)
    COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()

BEGIN_CONNECTION_POINT_MAP(CBase)
    CONNECTION_POINT_ENTRY(__uuidof(_IBaseEvents))
END_CONNECTION_POINT_MAP()
// ISupportsErrorInfo
    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);


    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }
};

OBJECT_ENTRY_AUTO(__uuidof(Base), CBase)
like image 916
Qwertie Avatar asked Nov 17 '08 17:11

Qwertie


1 Answers

Just a suggestion - if your COM object does not need to do anything special with COM related stuff then you can implement code such that the real logic that your base COM class does is encapsulated in another plain old C++ class say CBaseLogic.

CBaseLogic : IBase

class ATL_NO_VTABLE CBase :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CBase, &CLSID_Base>,
    public ISupportErrorInfo,
    public IConnectionPointContainerImpl<CBase>,
    public CProxy_IBaseEvents<CBase>,
    public IDispatchImpl<IBase, &IID_IBase, &LIBID_ExampleLib
{
CBaseLogic m_LogicObj; /* Method calls are simply forwarded to this member */
};


CDerivedLogic : public CBaseLogic

class ATL_NO_VTABLE CDerived :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CDerived, &CLSID_Base>,
    public ISupportErrorInfo,
    public IConnectionPointContainerImpl<CDerived>,
    public CProxy_IBaseEvents<CDerived>,
    public IDispatchImpl<IBase, &IID_IBase, &LIBID_ExampleLib
{
CDerivedLogic m_LogicObj;
};

This achieves what you are trying to do with the added advantage of

  1. Keeps your real program logic separate from the infrastructure / packaging (COM)
  2. Makes the real logic platform independent.
  3. Future maintainer need not understand your clever COM hack
  4. Keeps your program logic clean and away from the COM syntax, improving readability
  5. Makes re-use of real logic easier in other forms of packaging eg as a C DLL
like image 77
computinglife Avatar answered Sep 23 '22 23:09

computinglife