Figure 1   ISnapIn Interface Methods

Method Description
HINSTANCE GetResourceInstance(void) Returns a handle to the module that contains the string and bitmap resources used to add the snap-in to the menu bar and toolbar. You can return NULL if the snap-in won't appear as a menu item.
int GetMenuTextID(void) Returns the resource ID of the menu item text for the snap-in. If you don't want the snap-in to appear as a menu item, you should return –1.
int GetMessageTextID(void) Returns the resource ID of the status bar text. To provide a tooltip, place that text at the end of the status bar text, separated by \n. If you don't want text to appear in the status bar, you should return –1. This method is only called if the snap-in appears as a menu item.
int GetBitmapID(nSize) Returns the resource ID of the bitmap to be displayed in the application toolbar. Since the application may support various toolbar sizes, the button size is passed as a parameter. If you don't want the snap-in to appear in the toolbar, or if you don't support a particular bitmap size, you should return –1. This method is only called if the snap-in appears as a menu item.
BOOL SupportsInterface(IUnknown* lpUnk) Although an application should only load snap-ins that are marked in the registry as supporting a compatible interface, this method provides an extra safeguard. The application passes this method its context interface immediately after the snap-in is loaded. If the snap-in cannot successfully query an interface that it recognizes, it returns FALSE.
void OnStateChange(IUnknown* lpUnk) Called whenever the state of an application changes in a way that affects the snap-in. The application passes this method a pointer to its context interface.
void IsEnabled(IUnknown* lpUnk) Called by the application to determine whether or not the snap-in menu item should be enabled. In an MFC application, this method is called in response to an ON_UPDATE_ COMMAND_UI message. Thus, depending upon application context, a snap-in may be unavailable to the user.
void OnCommand(IUnknown* lpUnk) Called when the user selects the snap-in from the menu bar or toolbar. The application passes this method a pointer to its context interface.


Figure 5   CATID_ISnapIn and ISnapIn Declarations


 // Copyright (c) 1997, Microsoft Systems Journal
 // Author: Steve Zimmerman
 //
 
 // ISnapIn Interface Definition:
 // {6AE74760-83C6-11D0-A2A7-000000000000}
 
 DEFINE_GUID(IID_ISnapIn,
     0x6ae74760, 0x83c6, 0x11d0, 0xa2, 0xa7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);
 
 #define CATID_ISnapIn IID_ISnapIn
 
 DECLARE_INTERFACE_(ISnapIn, IUnknown)
 {
     STDMETHOD_(BOOL, SupportsInterface)(THIS_ IUnknown* lpUnk) PURE;
     STDMETHOD_(HINSTANCE, GetResourceInstance) (THIS_) PURE;
     STDMETHOD_(int, GetMenuTextID)(THIS_) PURE;
     STDMETHOD_(int, GetMessageTextID)(THIS_) PURE;
     STDMETHOD_(int, GetBitmapID)(THIS_ UINT nSize) PURE;
     STDMETHOD_(BOOL, IsEnabled)(THIS_ IUnknown* lpUnk) PURE;
     STDMETHOD_(void, OnStateChange)(THIS_ IUnknown* lpUnk) PURE;
     STDMETHOD_(void, OnCommand)(THIS_ IUnknown* lpUnk) PURE;
 };

Figure 6   CSnapInFrame and CSnapIn Classes

Class
Explanation
CSnapInFrame
Derived from CFrameWnd, this class looks up the compatible snap-ins in the registry (using the ICatInformation interface), creates a snap-in toolbar, routes command messages to the snap-in, and performs special handling required to enable the snap-in status bar messages and tooltips.
CSnapIn
Creates an instance of the specified snap-in class and provides a light wrapper around the ISnapIn interface. Adds the snap-in menu item and toolbar button to the application's menu bar and toolbar.


Figure 7   Header File for IrichDocContext


 // Copyright (c) 1997, Microsoft Systems Journal
 // Author: Steve Zimmerman
 //
 // IRichDocContext Interface Definition:
 // {305BB760-8993-11D0-A2C4-000000000000}
 
 DEFINE_GUID(IID_IRichDocContext, 
     0x305bb760, 0x8993, 0x11d0, 0xa2, 0xc4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);
 
 #define CATID_IRichDocContext IID_IRichDocContext
 
 DECLARE_INTERFACE_(IRichDocContext, IUnknown)
 {
     STDMETHOD_(HWND, GetRichEditCtrl)() PURE;
     STDMETHOD_(void, SetStatusText)(LPCTSTR) PURE;
 };

Figure 8   Functions Added to CmainFrame


 // Changes to the CMainFrame class
 //
 
 IUnknown* CMainFrame::GetSnapInContext(int nMsg)
 {
     // This function is called whenever we need to expose
     // an interface to the snap-in. If this application
     // has just called OnStateChange, which results in a
     // call to this function, nMsg will be an application
     // defined value that gives us added flexibility.
     // Otherwise, nMsg is zero. In the case of WordPad, we
     // always return the IRichDocContext interface pointer.
     
     return &m_xContextObj;
 }
 
 int CMainFrame::GetSupportedCategories(GUID** ppCatIDs)
 {
     // CMainFrame supports
         
     static CATID CatIDs[1];
     CatIDs[0] = CATID_IRichDocContext;
     *ppCatIDs = CatIDs;
     return 1;
 }
 
 BEGIN_INTERFACE_MAP(CMainFrame, CSnapInFrame)
     INTERFACE_PART(CMainFrame, IID_IRichDocContext, ContextObj)
 END_INTERFACE_MAP()
   
 HWND FAR EXPORT CMainFrame::XContextObj::GetRichEditCtrl()
 {
     METHOD_PROLOGUE(CMainFrame, ContextObj)
     CRichEditView* pView =
         DYNAMIC_DOWNCAST(CRichEditView, pThis->GetActiveView());
     ASSERT(pView);
     return pView->GetRichEditCtrl().GetSafeHwnd();
 }
 
 void FAR EXPORT CMainFrame::XContextObj::SetStatusText(LPCTSTR lpText)
 {
     METHOD_PROLOGUE(CMainFrame, ContextObj)
     pThis->SetMessageText(lpText);
 }
 
 ULONG FAR EXPORT CMainFrame::XContextObj::AddRef()
 {
     METHOD_PROLOGUE(CMainFrame, ContextObj)
     return pThis->ExternalAddRef();
 }
 
 ULONG FAR EXPORT CMainFrame::XContextObj::Release()
 {
     METHOD_PROLOGUE(CMainFrame, ContextObj)
     return pThis->ExternalRelease();
 }
 
 HRESULT FAR EXPORT CMainFrame::XContextObj::QueryInterface(
     REFIID iid, void FAR* FAR* ppvObj)
 {
     METHOD_PROLOGUE(CMainFrame, ContextObj)
     return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
 }

Figure 9   The CSnapInFrame Class

SnapFrm.h


 // Copyright (c) 1997, Microsoft Systems Journal
 // Author: Steve Zimmerman
 //
 // SnapFrm.h : header file
 //
 
 class CSnapIn;
 class CSnapInManager;
 interface ICatInformation;
 interface IEnumCLSID;
 
 class CSnapInFrame : public CFrameWnd
 {
 protected:
     DECLARE_DYNAMIC(CSnapInFrame);
     CTypedPtrArray<CPtrArray, CSnapIn*> m_snapIn;
     CToolBar m_snapInBar;
 
     void HideSnapInBar();
 
     virtual ~CSnapInFrame();
     virtual int CreateSnapInBar();
     virtual int AddMenuEntries();
     virtual BOOL GetNextSnapInClsID(ICatInformation** ppCatInfo,
         IEnumCLSID** ppEnum, CLSID* pClsID);
     virtual IUnknown* GetSnapInContext(int nMsg) = 0;
     virtual int GetSupportedCategories(GUID** ppCatIDs) = 0;
 
     //{{AFX_MSG(CSnapInFrame)
     afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
     //}}AFX_MSG
     DECLARE_MESSAGE_MAP()
 
     afx_msg void OnUpdateViewSnapInBar(CCmdUI* pCmdUI);
     afx_msg BOOL OnViewSnapInBarCheck(UINT nID);
     afx_msg void OnUpdateSnapIn(CCmdUI* pCmdUI);
     afx_msg void OnSnapIn(UINT nID);
     afx_msg BOOL OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult);
 
 public:
     void OnStateChange(int nMsg);
 
     //{{AFX_VIRTUAL(CSnapInFrame)
     public:
     virtual void ActivateFrame(int nCmdShow = -1);
     //}}AFX_VIRTUAL
     virtual void GetMessageString(UINT nID, CString& rMessage) const;
 };
 
 // These must be defined in order for CSnapInFrame to
 // compile correctly. However, you may define them as
 // you wish in resource.h if these values conflict
 // with yours.
 
 #ifndef ID_VIEW_SNAPINBAR
 #define ID_VIEW_SNAPINBAR               59999
 #define ID_TOOLS_START                  60000
 #define ID_TOOLS_END                    60100
 #endif
SnapFrm.cpp

 // Copyright (c) 1997, Microsoft Systems Journal
 // Author: Steve Zimmerman
 //
 // SnapFrm.cpp : implementation file
 //
 
 #include "stdafx.h"
 #include "..\resource.h"
 #include <comcat.h>
 #include <afxtempl.h>
 
 #include "ISnapIn.h"
 #include "SnapFrm.h"
 #include "SnapIn.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #undef THIS_FILE
 static char THIS_FILE[] = __FILE__;
 #endif
 
 /////////////////////////////////////////////////////////////////////////////
 // CSnapInFrame
 
 IMPLEMENT_DYNAMIC(CSnapInFrame, CFrameWnd)
 
 CSnapInFrame::~CSnapInFrame()
 {
     for (int nLoop = 0; nLoop < m_snapIn.GetSize(); nLoop++)
         delete m_snapIn[nLoop];
 }
 
 int CSnapInFrame::CreateSnapInBar()
 {
     EnableDocking(CBRS_ALIGN_ANY);
     m_snapInBar.Create(this, WS_CHILD|WS_VISIBLE|CBRS_TOP,
         ID_VIEW_SNAPINBAR);
 
     HDC screenDC = ::GetDC(NULL);
     BOOL bLargeIcons = GetDeviceCaps(screenDC, LOGPIXELSX) >= 120;
     ::ReleaseDC(NULL, screenDC);
     if (bLargeIcons)
         m_snapInBar.SetSizes(CSize(31,30), CSize(24,24));
     else
         m_snapInBar.SetSizes(CSize(23,22), CSize(16,16));
 
     m_snapInBar.SetBarStyle(m_snapInBar.GetBarStyle() |
         CBRS_TOOLTIPS |    CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
     m_snapInBar.EnableDocking(CBRS_ALIGN_ANY);
     DockControlBar(&m_snapInBar);
     return bLargeIcons ? 24 : 16;
 }
 
 #define VIEW_MENU_POSITION        2
 #define TOOLS_MENU_POSITION       5
 
 int CSnapInFrame::AddMenuEntries()
 {
     CMenu* pSubMenu = GetMenu()->GetSubMenu(VIEW_MENU_POSITION);
     ASSERT(pSubMenu);
     pSubMenu->InsertMenu(0, MF_BYPOSITION|MF_STRING|MF_CHECKED,
         ID_VIEW_SNAPINBAR, _T("Snap-&In Bar"));
 
     HMENU hMenu = ::CreateMenu();
     GetMenu()->InsertMenu(TOOLS_MENU_POSITION, MF_BYPOSITION|MF_POPUP,
         (UINT) hMenu, _T("&Tools"));
 
     return TOOLS_MENU_POSITION;
 }    
 
 void CSnapInFrame::HideSnapInBar()
 {
     CControlBar* pBar = GetControlBar(ID_VIEW_SNAPINBAR);
     if (pBar != NULL)
         ShowControlBar(pBar, FALSE, FALSE);
 }
 
 void CSnapInFrame::OnStateChange(int nMsg)
 {
     for (int nLoop = 0; nLoop < m_snapIn.GetSize(); nLoop++)
     {
         ISnapIn* pInt = m_snapIn[nLoop]->Interface();
         pInt->OnStateChange(GetSnapInContext(nMsg));
     }
 }
 
 BOOL CSnapInFrame::GetNextSnapInClsID(ICatInformation** ppCatInfo,
     IEnumCLSID** ppEnum, CLSID* pClsID)
 {
     ASSERT(ppCatInfo && ppEnum);
     
     // We get a pointer to ICatInformation so that we can find all
     // of the compatible SnapIns in the registry.
     
     if (*ppCatInfo == NULL)
     {
         HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
             CLSCTX_INPROC_SERVER, IID_ICatInformation, (LPVOID*) ppCatInfo);
         if (hr != S_OK)
             return FALSE;
     }
 
     // We only enumerate the SnapIns that support CATID_ISnapIn
     // and are compatible with this application.
 
     if (*ppEnum == NULL)
     {
         CATID* pCatIDs;
         int reqCatIDs = GetSupportedCategories(&pCatIDs);
 
         CATID snapInCatID = CATID_ISnapIn;
         HRESULT hr = (*ppCatInfo)->EnumClassesOfCategories(1, &snapInCatID,
             reqCatIDs, pCatIDs, ppEnum);
         if (hr != S_OK)
         {
             (*ppCatInfo)->Release();
             return FALSE;
         }
 
         (*ppEnum)->Reset();
     }
 
     ULONG lFetched;
     if ((*ppEnum)->Next(1, pClsID, &lFetched) != S_OK)
     {
         (*ppEnum)->Release();
         (*ppCatInfo)->Release();
         return FALSE;
     }
 
     return TRUE;
 }
 
 BEGIN_MESSAGE_MAP(CSnapInFrame, CFrameWnd)
     //{{AFX_MSG_MAP(CSnapInFrame)
     ON_WM_CREATE()
     //}}AFX_MSG_MAP
     ON_UPDATE_COMMAND_UI(ID_VIEW_SNAPINBAR, OnUpdateViewSnapInBar)
     ON_COMMAND_EX(ID_VIEW_SNAPINBAR, OnViewSnapInBarCheck)
     ON_UPDATE_COMMAND_UI_RANGE(ID_TOOLS_START, ID_TOOLS_END, OnUpdateSnapIn)
     ON_COMMAND_RANGE(ID_TOOLS_START, ID_TOOLS_END, OnSnapIn)
     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
 END_MESSAGE_MAP()
 
 /////////////////////////////////////////////////////////////////////////////
 // CSnapInFrame message handlers
 
 int CSnapInFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
 {
     if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
         return -1;
 
     int nBmpSize = CreateSnapInBar();
 
     CLSID clsID;
     IEnumCLSID* pEnum = NULL;
     ICatInformation* pCatInfo = NULL;
 
     int nSubMenu;
     int nIndex = 0;
     while (GetNextSnapInClsID(&pCatInfo, &pEnum, &clsID))
     {
         CSnapIn* pSnapIn = new CSnapIn(clsID, nIndex + ID_TOOLS_START);
         if (!pSnapIn->Interface() ||
             !pSnapIn->Interface()->SupportsInterface(GetSnapInContext(0)))
         {
             delete pSnapIn;
             continue;
         }
 
         if (m_snapIn.GetSize() == 0)
             nSubMenu = AddMenuEntries();
 
         ASSERT(GetMenu()->GetSubMenu(nSubMenu));
         if (pSnapIn->AddMenuItem(GetMenu()->GetSubMenu(nSubMenu)))
             pSnapIn->AddToolbarButton(m_snapInBar, nBmpSize);
         m_snapIn.Add(pSnapIn);
         nIndex++;
     }
 
     return 0;
 }
 
 void CSnapInFrame::ActivateFrame(int nCmdShow) 
 {
     if (m_snapIn.GetSize() == 0)
         HideSnapInBar();
     
     CFrameWnd::ActivateFrame(nCmdShow);
 }
 
 void CSnapInFrame::GetMessageString(UINT nID, CString& rMessage) const
 {
     if (nID < ID_TOOLS_START || nID > ID_TOOLS_END)
     {
         CFrameWnd::GetMessageString (nID, rMessage);
         return;
     }
 
     CSnapIn* pSnapIn = m_snapIn[nID - ID_TOOLS_START];
     HINSTANCE myInst = AfxGetResourceHandle();
     AfxSetResourceHandle(pSnapIn->Interface()->GetResourceInstance());
     nID = pSnapIn->Interface()->GetMessageTextID();
     CFrameWnd::GetMessageString(nID, rMessage);
     AfxSetResourceHandle(myInst);
 }
 
 void CSnapInFrame::OnUpdateViewSnapInBar(CCmdUI* pCmdUI)
 {
     CControlBar* pBar = GetControlBar(ID_VIEW_SNAPINBAR);
     if (pBar != NULL)
     {
         pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0);
         return;
     }
     pCmdUI->ContinueRouting();
 }
 
 BOOL CSnapInFrame::OnViewSnapInBarCheck(UINT nID)
 {
     CControlBar* pBar = GetControlBar(ID_VIEW_SNAPINBAR);
     if (pBar != NULL)
     {
         ShowControlBar(pBar, (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE);
         return TRUE;
     }
     return FALSE;
 }
 
 void CSnapInFrame::OnUpdateSnapIn(CCmdUI* pCmdUI)
 {
     CSnapIn* pSnapIn = m_snapIn[pCmdUI->m_nID - ID_TOOLS_START];
     pCmdUI->Enable(pSnapIn->Interface()->
         IsEnabled(GetSnapInContext(0)));
 }
 
 void CSnapInFrame::OnSnapIn(UINT nID)
 {
     CSnapIn* pSnapIn = m_snapIn[nID - ID_TOOLS_START];
     pSnapIn->Interface()->OnCommand(GetSnapInContext(0));
 }
 
 BOOL CSnapInFrame::OnToolTipText(UINT nID, NMHDR* pNMHDR, LRESULT* pResult)
 {
     if (pNMHDR->idFrom < ID_TOOLS_START || pNMHDR->idFrom > ID_TOOLS_END)
         return CFrameWnd::OnToolTipText(nID, pNMHDR, pResult);
 
     CSnapIn* pSnapIn = m_snapIn[pNMHDR->idFrom - ID_TOOLS_START];
     HINSTANCE myInst = AfxGetResourceHandle();
     AfxSetResourceHandle(pSnapIn->Interface()->GetResourceInstance());
     pNMHDR->idFrom = pSnapIn->Interface()->GetMessageTextID();
     BOOL bResult = CFrameWnd::OnToolTipText(nID, pNMHDR, pResult);
     AfxSetResourceHandle(myInst);
     
     return bResult;
 }

Figure 11   Component Category Helper Functions


 // Copyright (c) 1997, Microsoft Systems Journal
 // Author: Steve Zimmerman
 //
 // SnapIns.cpp : Implementation of DLL Exports.
 
 // You will need the NT SUR Beta 2 SDK or VC 4.2 in order to build this 
 // project.  This is because you will need MIDL 3.00.15 or higher and new
 // headers and libs.  If you have VC 4.2 installed, then everything should
 // already be configured correctly.
 
 // Note: Proxy/Stub Information
 //        To build a separate proxy/stub DLL, 
 //        run nmake -f SnapInsps.mak in the project directory.
 
 #include "stdafx.h"
 #include "resource.h"
 #include "initguid.h"
 #include "comcat.h"
 
 #include "ISnapIn.h"
 #include "IRichDoc.h"
 #include "RichDoc.h"
 #include "WordCount.h"
 #include "RemoveDup.h"
 #include "Correct.h"
 
 HRESULT RegisterComponentCategory(CATID catid, TCHAR* catDescription,
     BOOL bRegister = TRUE);
 HRESULT RegisterClassReqCategory(const CLSID* rclsid, CATID rgcatid,
     BOOL bRegister = TRUE);
 HRESULT RegisterClassImplCategory(const CLSID* rclsid, CATID rgcatid,
     BOOL bRegister = TRUE);
 
 #define IID_DEFINED
 
 CComModule _Module;
 
 BEGIN_OBJECT_MAP(ObjectMap)
     OBJECT_ENTRY(CLSID_CWordCount, CWordCount)
     OBJECT_ENTRY(CLSID_CRemoveDup, CRemoveDup)
     OBJECT_ENTRY(CLSID_CAutoCorrect, CAutoCorrect)    
 END_OBJECT_MAP()
 
 class CMyApp : public CWinApp
 {
 public:
     virtual BOOL InitInstance();
     virtual int ExitInstance();
 };
 
 CMyApp theApp;
 
 BOOL CMyApp::InitInstance()
 {
     _Module.Init(ObjectMap, m_hInstance);
     return CWinApp::InitInstance();
 }
 
 int CMyApp::ExitInstance()
 {
     _Module.Term();
     return CWinApp::ExitInstance();
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Used to determine whether the DLL can be unloaded by OLE
 
 STDAPI DllCanUnloadNow(void)
 {
     AFX_MANAGE_STATE(AfxGetStaticModuleState());
     return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ? S_OK : S_FALSE;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Returns a class factory to create an object of the requested type
 
 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
 {
     return _Module.GetClassObject(rclsid, riid, ppv);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // DllRegisterServer - Adds entries to the system registry
 
 STDAPI DllRegisterServer(void)
 {
     // First we register the ISnapIn and IRichDocContext
     // interfaces as special categories. For simplicity,
     // I just use the CLSIDs as the CATIDs. In your code,
     // you should register ISnapIn (and IRichDocContext if
     // you happen to use it) using the same text description
     // given here. We can't unregister these categories
     // since another module might require them.
 
     RegisterComponentCategory(CATID_ISnapIn, _T("Snap-Ins"));
     RegisterComponentCategory(CATID_IRichDocContext,
         _T("Snap-Ins that support the IRichDocContext interface"));
 
     // Now we register each control as implementing ISnapIn
     // and requiring that its container support IRichDocContext
 
     _ATL_OBJMAP_ENTRY* pEntry = _Module.m_pObjMap;
     while (pEntry->pclsid != NULL)
     {
         RegisterClassImplCategory(pEntry->pclsid, CATID_ISnapIn);
         RegisterClassReqCategory(pEntry->pclsid, CATID_IRichDocContext);
         pEntry++;
     }
 
     // register all the other stuff
     
     return _Module.RegisterServer(FALSE);    // No typelib
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // DllUnregisterServer - Removes entries from the system registry
 
 STDAPI DllUnregisterServer(void)
 {
     _Module.UnregisterServer();
     return S_OK;
 }
 
 HRESULT RegisterComponentCategory(CATID catid,
     TCHAR* catDescription, BOOL bRegister)
 {
     ICatRegister* pcr = NULL;
     HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
         NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
     if (FAILED(hr))
         return hr;
 
     // Make sure the HKCR\Component Categories\{..catid...}
     // key is registered
 
     CATEGORYINFO catinfo;
     catinfo.catid = catid;
     catinfo.lcid = 0x0409; // English is all for now
 
     // Make sure the provided description is not too long.
     // Only copy the first 127 characters if it is
 
     USES_CONVERSION;
     int len = min(_tcslen(catDescription), 127);
     wcsncpy(catinfo.szDescription, T2W(catDescription), len);
     catinfo.szDescription[len] = 0;
 
     if (bRegister)
         hr = pcr->RegisterCategories(1, &catinfo);
     else 
         hr = pcr->UnRegisterCategories(1, &catid);
 
     pcr->Release();
     return hr;
 }
 
 HRESULT RegisterClassReqCategory(const CLSID* pclsid,
     CATID rgcatid, BOOL bRegister)
 {
     _ASSERTE(pclsid);
     
     ICatRegister* pcr = NULL;
     HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
         NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
     if (FAILED(hr))
         return hr;
 
     return bRegister ? pcr->RegisterClassReqCategories(*pclsid, 1, &rgcatid)
         : pcr->UnRegisterClassReqCategories(*pclsid, 1, &rgcatid);
 }
 
 HRESULT RegisterClassImplCategory(const CLSID* pclsid,
     CATID rgcatid, BOOL bRegister)
 {
     _ASSERTE(pclsid);
 
     ICatRegister* pcr = NULL;
     HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
         NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
     if (FAILED(hr))
         return hr;
 
     return bRegister ? pcr->RegisterClassImplCategories(*pclsid, 1, &rgcatid)
         : pcr->UnRegisterClassImplCategories(*pclsid, 1, &rgcatid);
 }