Figure 7    Declaration of CIEHlprObj


// IEHlprObj.h : Declaration of the CIEHlprObj

#ifndef __IEHLPROBJ_H_
#define __IEHLPROBJ_H_

#include "resource.h"       // main symbols
#include "ExDisp.h"
#include "EventsDlg.h"

/////////////////////////////////////////////////////////////////////////////
// CIEHlprObj
class ATL_NO_VTABLE CIEHlprObj : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CIEHlprObj, &CLSID_IEHlprObj>,
    public IObjectWithSiteImpl<CIEHlprObj>,
    public IDispatchImpl<IIEHlprObj, &IID_IIEHlprObj, 
                          &LIBID_IEHELPERLib>
{
public:
   DECLARE_REGISTRY_RESOURCEID(IDR_IEHLPROBJ)
   DECLARE_NOT_AGGREGATABLE(CIEHlprObj)

   BEGIN_COM_MAP(CIEHlprObj)
      COM_INTERFACE_ENTRY(IIEHlprObj)
      COM_INTERFACE_ENTRY(IDispatch)
      COM_INTERFACE_ENTRY_IMPL(IObjectWithSite)
   END_COM_MAP()

// IIEHlprObj
public:
   void Navigate(LPTSTR szURL);
   void GoForward();
   void GoBack();

   //
   // CIEHlprObj Methods
   //
   CIEHlprObj() : m_dlgEvents(this) {}
   ~CIEHlprObj();

   //
   // IDispatch Methods
   //
   STDMETHOD(Invoke)(DISPID dispidMember,REFIID riid, LCID lcid,
                     WORD wFlags, DISPPARAMS* pdispparams,
                     VARIANT* pvarResult, EXCEPINFO* pexcepinfo,
                     UINT* puArgErr);

   //
   // IOleObjectWithSite Methods
   //
   STDMETHOD(SetSite)(IUnknown *pUnkSite);

private:
   CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> m_spWebBrowser2;
   CEventsDlg m_dlgEvents;

   DWORD m_dwCookie;   // Connection Token - used for
                       // Advise and Unadvise

    
   enum ConnectType { Advise, Unadvise };   // What to do when managing 
                                            // the connection

   BOOL ManageConnection(enum ConnectType eConnectType);
};

#endif //__IEHLPROBJ_H_

Figure 8   SetSite Implementation


STDMETHODIMP CIEHlprObj::SetSite(IUnknown *pUnkSite)
{
   USES_CONVERSION;
   HRESULT hr = E_FAIL;

   if (!pUnkSite)
      ATLTRACE("\nSetSite(): pUnkSite is NULL\n\n");
   else
   {
      // Query pUnkSite for the IWebBrowser2 interface.
      m_spWebBrowser2 = pUnkSite;

      if (m_spWebBrowser2)
      {
         // Create the events dialog box
         m_dlgEvents.Create(::GetDesktopWindow());
         m_dlgEvents.ShowWindow(SW_SHOWNORMAL);

         // Connect to the browser in order to handle events.
         if (!ManageConnection(Advise))
         {
            ATLTRACE("\n%s: %s\n\n",
                     "SetSite(): Failure connecting to Browser",
                     pszAppName);
         }
      }
   }

   return hr;

Figure 9    Invoke


STDMETHODIMP CIEHlprObj::Invoke(DISPID dispidMember, REFIID riid,
                                LCID lcid, WORD wFlags,
                                DISPPARAMS* pDispParams,
                                VARIANT* pvarResult,
                                EXCEPINFO*  pExcepInfo, UINT* puArgErr)
{
   USES_CONVERSION;
   strstream strEventInfo;

   if (!pDispParams)
      return E_INVALIDARG;

   // Get the current URL
   //  
   LPOLESTR lpURL = NULL;
   m_spWebBrowser2->get_LocationURL(&lpURL);

   switch (dispidMember)
   {
      // The parameters for this DISPID are as follows:
      // [0]: Cancel flag  - VT_BYREF|VT_BOOL
      // [1]: HTTP headers - VT_BYREF|VT_VARIANT
      // [2]: Address of HTTP POST data  - VT_BYREF|VT_VARIANT 
      // [3]: Target frame name - VT_BYREF|VT_VARIANT 
      // [4]: Option flags - VT_BYREF|VT_VARIANT
      // [5]: URL to navigate to - VT_BYREF|VT_VARIANT
      // [6]: An object that evaluates to the top-level or frame
      //      WebBrowser object corresponding to the event. 
      //
      case DISPID_BEFORENAVIGATE2:
         strEventInfo << "BeforeNavigate2: ";

         if (pDispParams->cArgs >= 5 &&
             pDispParams->rgvarg[5].vt == (VT_BYREF|VT_VARIANT))
         {
            CComVariant varURL(*pDispParams->rgvarg[5].pvarVal);
            varURL.ChangeType(VT_BSTR);

            strEventInfo << OLE2T(varURL.bstrVal);
         }
         else
            strEventInfo << "NULL";

         strEventInfo << ends;
         break;

      // The parameters for this DISPID:
      // [0]: URL navigated to - VT_BYREF|VT_VARIANT
      // [1]: An object that evaluates to the top-level or frame
      //      WebBrowser object corresponding to the event. 
      //
      case DISPID_NAVIGATECOMPLETE2:
         if (pDispParams->rgvarg[0].vt == (VT_BYREF|VT_VARIANT))
         {
            CComVariant varURL(*pDispParams->rgvarg[0].pvarVal);
            varURL.ChangeType(VT_BSTR);
  
            strEventInfo << "NavigateComplete2: "
                         << OLE2T(varURL.bstrVal)
                         << ends;
         }
         break;

      // The parameters for this DISPID:
      // [0]: New status bar text - VT_BSTR
      //
      case DISPID_STATUSTEXTCHANGE:
         LPOLESTR lpStatusText;

         m_spWebBrowser2->get_StatusText(&lpStatusText);
         strEventInfo << "StatusTextChange: ";

         if (!strcmp(OLE2T(lpStatusText), ""))
            strEventInfo << "NULL";
         else
            strEventInfo << OLE2T(lpStatusText);

         strEventInfo << ends;
         break;

      // The parameters for this DISPID:
      // [0]: Maximum progress - VT_I4
      // [1]: Amount of total progress - VT_I4
      //
      case DISPID_PROGRESSCHANGE:
         strEventInfo << "ProgressChange: ";

         if (pDispParams->cArgs == 0)
            strEventInfo << "NULL";
         else
         {
            if (pDispParams->rgvarg[0].vt == VT_I4)
               strEventInfo << pDispParams->rgvarg[0].lVal;

            if (pDispParams->cArgs > 1 && pDispParams->rgvarg[1].vt == VT_I4)
               strEventInfo << ", " << pDispParams->rgvarg[1].lVal;
         }

         strEventInfo << ends;
         break;

      case DISPID_DOCUMENTCOMPLETE:
         strEventInfo << "DocumentComplete" << ends;
         break;

      case DISPID_DOWNLOADBEGIN:
         strEventInfo << "DownloadBegin" << ends;
         break;

      case DISPID_DOWNLOADCOMPLETE:
         strEventInfo << "DownloadComplete" << ends;
         break;

      // The parameters for this DISPID:
      // [0]: Enabled state - VT_BOOL
      // [1]: Command identifier - VT_I4

      //
      case DISPID_COMMANDSTATECHANGE:
         strEventInfo << "CommandStateChange: ";

         if (pDispParams->cArgs == 0)
            strEventInfo << "NULL";
         else
         {
            if (pDispParams->rgvarg[0].vt == VT_BOOL)
               strEventInfo << ((pDispParams->rgvarg[0].boolVal == 
                                 VARIANT_TRUE) ? "True" : "False");

            if (pDispParams->cArgs > 1 && pDispParams->rgvarg[1].vt == VT_I4)
               strEventInfo << ", " << pDispParams->rgvarg[1].lVal;
         }

         strEventInfo << ends;
         break;

      case DISPID_NEWWINDOW2:
         strEventInfo << "NewWindow2" << ends;
         break;

      // The parameters for this DISPID:
      // [0]: Document title - VT_BSTR
      //
      case DISPID_TITLECHANGE:
         strEventInfo << "TitleChange: ";

         if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == VT_BSTR)
            strEventInfo << OLE2T(pDispParams->rgvarg[0].bstrVal);
         else
            strEventInfo << "NULL";

         strEventInfo << ends;
         break;

      // The parameters for this DISPID:
      // [0]: Name of property that changed - VT_BSTR
      //
      case DISPID_PROPERTYCHANGE:
         strEventInfo << "PropertyChange: ";

         if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == VT_BSTR)
            strEventInfo << OLE2T(pDispParams->rgvarg[0].bstrVal);
         else
            strEventInfo << "NULL";

         strEventInfo << ends;
         break;

      // The parameters for this DISPID:
      // [0]: Address of cancel flag - VT_BYREF|VT_BOOL
      //
      case DISPID_QUIT:
         strEventInfo << "Quit" << ends;

         ManageConnection(Unadvise);
         m_dlgEvents.DestroyWindow();
         break;

      default:
         strEventInfo << "Unknown Event" << dispidMember << ends;
         break;
   }

   m_dlgEvents.AddEventToList(strEventInfo.str());

   return S_OK;
}

Figure 10    IEHlprObj.rgs


HKCR
{
   IEHlprObj.IEHlprObj.1 = s 'IEHlprObj Class'
   {
      CLSID = s '{CE7C3CF0-4B15-11D1-ABED-709549C10000}'
   }
   IEHlprObj.IEHlprObj = s 'IEHlprObj Class'
   {
      CurVer = s 'IEHlprObj.IEHlprObj.1'
   }
   NoRemove CLSID
   {
      ForceRemove {CE7C3CF0-4B15-11D1-ABED-709549C10000} = s 'IEHlprObj Class'
      {
         ProgID = s 'IEHlprObj.IEHlprObj.1'
         VersionIndependentProgID = s 'IEHlprObj.IEHlprObj'
         ForceRemove 'Programmable'
         InprocServer32 = s '%MODULE%'
         {
            val ThreadingModel = s 'Apartment'
         }
      }
   }
}

HKLM
{
   SOFTWARE
   {
      Microsoft
      {
       Windows
       {
            CurrentVersion
            {
               Explorer
               {
                  'Browser Helper Objects'
                   {
                      {CE7C3CF0-4B15-11D1-ABED-709549C10000}
                   }
               }
            }
         }
      }
   }
}