Extending ATL to Support the New MMC User Interface 

It's pretty easy to create SnapIn's for the MMC (Microsoft Management Console) using the ATL COM AppWizard. But the ATL classes don't support the new interfaces since MMC 1.1! So if you like to write SnapIn's using the new design of property sheet's and wizard's you have to extend the ATL classes. Here is how it works:  

First you need an extended abstract base class for the Snap'In-Items... 

class ATL_NO_VTABLE CSnapInItem2 : public CSnapInItem

{

public:

 STDMETHOD(GetWatermarks)(HBITMAP *lphWatermark,

                          HBITMAP *lphHeader,

                          HPALETTE *lphPalette,

                          BOOL *bStretch,

                          IUnknown* pUnk,

                          DATA_OBJECT_TYPES type) = 0;

};

...and a new implementation template! 

template 

class ATL_NO_VTABLE CSnapInItemImpl2 : public CSnapInItemImpl

{

public:

 STDMETHOD(GetWatermarks)(HBITMAP *lphWatermark,

                          HBITMAP *lphHeader,

                          HPALETTE *lphPalette,

                          BOOL *bStretch,

                          IUnknown* pUnk,

                          DATA_OBJECT_TYPES type)

 {

  ATLTRACENOTIMPL(_T("CSnapInItemImpl2::GetWatermarks"));

 }

};

Now we need to extend the template for the interface implementation! 

// IExtendPropertySheetImpl2

template 

class ATL_NO_VTABLE IExtendPropertySheetImpl2 

: public IExtendPropertySheetImpl

{

public:

 STDMETHOD(GetWatermarks)(LPDATAOBJECT pDataObject,

                          HBITMAP __RPC_FAR *lphWatermark,

                          HBITMAP __RPC_FAR *lphHeader,

                          HPALETTE __RPC_FAR *lphPalette,

                          BOOL __RPC_FAR *bStretch)

 {

  HRESULT hr = E_POINTER;

  ATLTRACE2(atlTraceSnapin, 

            0, 

            _T("IExtendPropertySheetImpl::GetWatermarks\n"));

  ATLASSERT(pDataObject != NULL);

  if (pDataObject == NULL)

  {

   ATLTRACE2(atlTraceSnapin, 

             0, 

             _T("IExtendPropertySheetImpl::GetWatermarks "

             "called with pDataObject==NULL\n"));

  }

  else

  {

   T*                pT = static_cast(this);

   CSnapInItem2*     pItem;

   DATA_OBJECT_TYPES type;

   hr = pT->m_pComponentData->GetDataClass(pDataObject, 

                                           (CSnapInItem**)&pItem, 

                                           &type);

   if (SUCCEEDED(hr))

   {

    hr = pItem->GetWatermarks(lphWatermark, 

                                 lphHeader, 

                                 lphPalette, 

                                 bStretch, 

                                 this, 

                                 type);

   }

  }

  return hr;

 }

};

OK, now you know how to extend the ATL. Here is how to use this new classes! First you have to change the base class in the AppWizard generated code (CSnapInItemImpl => CSnapInItemImpl2). Implement the new interface method here! 

class CMySnapInData : public CSnapInItemImpl2

{

 STDMETHOD(GetWatermarks)(HBITMAP *lphWatermark,

                          HBITMAP *lphHeader,

                          HPALETTE *lphPalette,

                          BOOL *bStretch,

                          IUnknown* pUnk,

                          DATA_OBJECT_TYPES type)

 {

  switch(type)

  {

   case CCT_SNAPIN_MANAGER:

   case CCT_SCOPE:

   case CCT_RESULT:

    *lphHeader = (HBITMAP)LoadImage(_Module.GetResourceInstance(), 

                                    MAKEINTRESOURCE(IDB_MYSNAPIN_HEADER), 

                                    IMAGE_BITMAP, 

                                    0, 0, 0);

    return S_OK;

   case CCT_UNINITIALIZED:

   default:

   break;

  }

  return E_UNEXPECTED;

 }

};

Use the new interface template 'IExtendPropertySheetImpl2' instead of 'IExtendPropertySheetImpl' in the AppWizard generated code for the Component and the SnapIn classes! You have to use the COM_INTERFACE_ENTRY2 macro for the inherited interface! 

class CMySnapInComponent : 

 public CComObjectRootEx,

 public CSnapInObjectRoot<2, CMySnapIn>,

 public IExtendPropertySheetImpl2,

 public IExtendContextMenuImpl,

 public IExtendControlbarImpl,

 public IPersistStreamInit,

 public IComponentImpl

{

public:

 BEGIN_COM_MAP(CMySnapInComponent)

  COM_INTERFACE_ENTRY(IComponent)

  COM_INTERFACE_ENTRY(IExtendPropertySheet)

  COM_INTERFACE_ENTRY2(IExtendPropertySheet2,IExtendPropertySheet)

  COM_INTERFACE_ENTRY(IExtendContextMenu)

  COM_INTERFACE_ENTRY(IExtendControlbar)

  COM_INTERFACE_ENTRY(IPersistStreamInit)

 END_COM_MAP()

};

class CMySnapIn : 

 public CComObjectRootEx,

 public CSnapInObjectRoot<1, CMySnapIn>,

 public IComponentDataImpl,

 public IExtendPropertySheetImpl2,

 public IExtendContextMenuImpl,

 public IPersistStreamInit,

 public CComCoClass

{

public:

 BEGIN_COM_MAP(CMySnapIn)

  COM_INTERFACE_ENTRY(IComponentData)

  COM_INTERFACE_ENTRY2(IExtendPropertySheet2,IExtendPropertySheet)

  COM_INTERFACE_ENTRY(IExtendContextMenu)

  COM_INTERFACE_ENTRY(IPersistStreamInit)

 END_COM_MAP()

};