Figure 5   MyBands

MyBands.h


////////////////////////////////////////////////////////////////
// Microsoft Systems Journal -- November 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
#include "Resource.h"
#include "BandObj.h"
#include "EditSearch.h"

//////////////////
// Application class: derive from CBandObjApp
class CMyBandsDll : public CBandObjDll {
public:
   CMyBandsDll();
   virtual ~CMyBandsDll();
   virtual BOOL InitInstance();
protected:
   DECLARE_MESSAGE_MAP()
};

DECLARE_SMARTPTR(IWebBrowser2);

//////////////////
// common base class for info and comm bands
class CMyIEBand : public CBandObj {
public:
   CMyIEBand(REFIID clsid);
   ~CMyIEBand();
   
protected:
   SPIWebBrowser2 m_spWebBrowser2;      // browser interface
   CString  m_message;                  // window text
   COLORREF m_bgColor;                  // background color
   CString  m_url;                      // where to go when clicked

   HRESULT  OnSetSite(IUnknown*);       // override to get web browser

   DECLARE_MESSAGE_MAP();
   afx_msg void OnPaint();
   afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
   afx_msg BOOL OnEraseBkgnd(CDC* pDC);
   afx_msg void OnCommand(UINT nID);
   DECLARE_DYNAMIC(CMyIEBand)
};

//////////////////
// Info band lives in IE left pane
class CMyInfoBand : public CMyIEBand {
public:
   CMyInfoBand();
   DECLARE_DYNCREATE(CMyInfoBand)
};


//////////////////
// Comm band lives in IE bottom pane
class CMyCommBand : public CMyIEBand {
public:
   CMyCommBand();
   DECLARE_DYNCREATE(CMyCommBand)
};

//////////////////
// Desk band lives in task bar
class CMyDeskBand : public CBandObj {
public:
   CMyDeskBand();
   ~CMyDeskBand();

protected:
   CEditSearch m_wndEdit;

   // override
   virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
      AFX_CMDHANDLERINFO* pHandlerInfo);

   afx_msg void OnPaint();
   afx_msg void OnSetFocus(CWnd* pOldWnd);
   afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
   afx_msg void OnSize(UINT nType, int cx, int cy);
   DECLARE_MESSAGE_MAP();
   DECLARE_DYNCREATE(CMyDeskBand)
};
MyBands.cpp

////////////////////////////////////////////////////////////////
// Microsoft Systems Journal -- November 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
//
#include "StdAfx.h"
#include "MyBands.h"
#include "Debug.h"
#include "TraceWin.h"
#include "resource.h"
#include "ComToys.h"
#include "IniFile.h"
#include <initguid.h> // so my GUIDs are created

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

BEGIN_MESSAGE_MAP(CMyBandsDll, CBandObjDll)
END_MESSAGE_MAP()

CMyBandsDll theApp;

// {4647E381-520B-11d2-A0D0-004033D0645D}
DEFINE_GUID(CLSID_MYINFOBAND,
0x4647e381, 0x520b, 0x11d2, 0xa0, 0xd0, 0x0, 0x40, 0x33, 0xd0, 0x64, 0x5d);

// {4647E382-520B-11d2-A0D0-004033D0645D}
DEFINE_GUID(CLSID_MYCOMMBAND,
0x4647e382, 0x520b, 0x11d2, 0xa0, 0xd0, 0x0, 0x40, 0x33, 0xd0, 0x64, 0x5d);

// {4647E383-520B-11d2-A0D0-004033D0645D}
DEFINE_GUID(CLSID_MYDESKBAND,
0x4647e383, 0x520b, 0x11d2, 0xa0, 0xd0, 0x0, 0x40, 0x33, 0xd0, 0x64, 0x5d);

CMyBandsDll::CMyBandsDll()
{
   CBandObj::bTRACE=TRUE; // TRACEing on for bandobj
}

CMyBandsDll::~CMyBandsDll()
{
}

//////////////////
// initialize: add each band class
BOOL CMyBandsDll::InitInstance()
{
   TRACEFN(_T("CMyBandsDll::InitInstance\n"));
// SetRegistryKey(_T("MSJ"));
   CIniFile::Use(this, CIniFile::LocalDir);

   VERIFY(AddBandClass(CLSID_MYINFOBAND,
      RUNTIME_CLASS(CMyInfoBand),
      CATID_InfoBand,
      IDR_INFOBAND));

   VERIFY(AddBandClass(CLSID_MYCOMMBAND,
      RUNTIME_CLASS(CMyCommBand),
      CATID_CommBand,
      IDR_COMMBAND));

   VERIFY(AddBandClass(CLSID_MYDESKBAND,
      RUNTIME_CLASS(CMyDeskBand),
      CATID_DeskBand,
      IDR_DESKBAND));

   return CBandObjDll::InitInstance();
}

//////////////// CMyIEBand ////////////////

IMPLEMENT_DYNAMIC(CMyIEBand, CBandObj)
BEGIN_MESSAGE_MAP(CMyIEBand, CBandObj)
   ON_WM_PAINT()
   ON_WM_LBUTTONDOWN()
   ON_WM_ERASEBKGND()
   ON_COMMAND_RANGE(ID_COMMAND1, ID_COMMAND2, OnCommand)
END_MESSAGE_MAP()

CMyIEBand::CMyIEBand(REFIID clsid) : CBandObj(clsid)
{
}

CMyIEBand::~CMyIEBand()
{
}

BOOL CMyIEBand::OnEraseBkgnd(CDC* pDC)
{
   CClientDC dc(this);
   CRect rc;
   GetClientRect(&rc);
   dc.FillSolidRect(&rc, m_bgColor);
   return TRUE;
}

void CMyIEBand::OnPaint()
{
   CPaintDC dc(this);
   CRect rc;
   GetClientRect(&rc);
   dc.SetTextColor(RGB(0,0,0));
   dc.SetBkMode(TRANSPARENT);
   dc.DrawText(m_message, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}

void CMyIEBand::OnCommand(UINT nID)
{
   CString s;
   s.Format(_T("Command %d received!"), nID-ID_COMMAND1+1);
   GetParent()->MessageBox(s, GetTitle(), MB_OK | MB_ICONINFORMATION);
   SetFocus();
}

//////////////////
// SetSite override gets web browser when Explorer sets itself as my site
HRESULT CMyIEBand::OnSetSite(IUnknown* pSite)
{
   HRESULT hr = CBandObj::OnSetSite(pSite);
   if (SUCCEEDED(hr)) {
      CComQIPtr<IServiceProvider> sp = pSite;
      if (sp)
         sp->QueryService(IID_IWebBrowserApp,
            IID_IWebBrowser2, (void**)&m_spWebBrowser2);
      else
         m_spWebBrowser2 = (LPUNKNOWN)NULL;
   }
   return hr;
}

//////////////////
// Mouse click: navigate to page
void CMyIEBand::OnLButtonDown(UINT nFlags, CPoint point)
{
   if (m_spWebBrowser2) {
      m_spWebBrowser2->Navigate(_bstr_t(m_url), NULL, NULL, NULL, NULL);
   }
}

//////////////// CMyCommBand ////////////////

IMPLEMENT_DYNCREATE(CMyCommBand, CMyIEBand)

CMyCommBand::CMyCommBand() : CMyIEBand(CLSID_MYCOMMBAND)
{
   m_strTitle.Empty();
   m_dbiDefault.ptMinSize = CPointL(-1,30);
   m_dbiDefault.ptMaxSize = CPointL(-1,30);
   m_dbiDefault.ptActual  = CPointL(100,30);
   m_url = _T("http://www.microsoft.com/mind");
   m_message = _T("Buy MInD");
   m_bgColor = RGB(255,0,128);
}

IMPLEMENT_DYNCREATE(CMyInfoBand, CMyIEBand)

CMyInfoBand::CMyInfoBand() : CMyIEBand(CLSID_MYINFOBAND)
{
   m_dbiDefault.dwModeFlags = DBIMF_VARIABLEHEIGHT;
   m_dbiDefault.ptActual = CPointL(10,-1);
   m_url = _T("http://www.microsoft.com/msj");
   m_message = _T("MSJ");
   m_bgColor = RGB(255,255,255);
}

//////////////// CMyDeskBand ////////////////

IMPLEMENT_DYNCREATE(CMyDeskBand, CBandObj)
BEGIN_MESSAGE_MAP(CMyDeskBand, CBandObj)
   ON_WM_CREATE()
   ON_WM_SIZE()
   ON_WM_SETFOCUS()
END_MESSAGE_MAP()

CMyDeskBand::CMyDeskBand() : CBandObj(CLSID_MYDESKBAND),
   m_wndEdit(_T("SearchStrings"))
{
   const CXDESIRED = 100;   // desired width = 100
   m_dbiDefault.ptActual  = CPointL(CXDESIRED,0);
   m_dbiDefault.dwModeFlags = DBIMF_VARIABLEHEIGHT;
}

CMyDeskBand::~CMyDeskBand()
{
}

//////////////////
// I'm being created: create edit control and set band obj
// context menu from edit search control
int CMyDeskBand::OnCreate(LPCREATESTRUCT lpcs)
{
   TRACE(_T("CMyDeskBand::OnCreate\n"));
   if (CBandObj::OnCreate(lpcs)==-1)
      return -1;
   m_wndEdit.Create(WS_VISIBLE|WS_CHILD, CRect(0,0,0,0), this, 1);
   m_wndEdit.CreateSearchMenu(m_contextMenu);
   return 0;
}

//////////////////
// Window was resized: adjust edit control
void CMyDeskBand::OnSize(UINT nType, int cx, int cy)
{
   TRACE(_T("CMyDeskBand::OnSize(%d,%d)\n"),cx,cy);
   CBandObj::OnSize(nType, cx, cy);
   CRect rc(CPoint(0,0),CSize(cx,cy));
   rc.DeflateRect(2,2);
   m_wndEdit.SetWindowPos(NULL, rc.left, rc.top, rc.Width(), rc.Height(), 0);
}

//////////////////
// I got focus: pass to edit control
void CMyDeskBand::OnSetFocus(CWnd* pOldWnd)
{
   CBandObj::OnSetFocus(pOldWnd);
   m_wndEdit.SetFocus();
}

//////////////////
// route commands through edit control
BOOL CMyDeskBand::OnCmdMsg(UINT a, int b, void* c, AFX_CMDHANDLERINFO* d)
{
   return m_wndEdit.OnCmdMsg(a, b, c, d) ? TRUE :
      CBandObj::OnCmdMsg(a, b, c, d);
}

Figure 7   IRegistrar Methods


//////////////////
// IRegistrar -- The eaisest way to deal with registration
//

IRegistrar : public IUnknown {
public:
    HRESULT STDMETHODCALLTYPE AddReplacement( 
    /* [in] */ LPCOLESTR key,
    /* [in] */ LPCOLESTR item) = 0;

    HRESULT STDMETHODCALLTYPE ClearReplacements( void) = 0;

    HRESULT STDMETHODCALLTYPE ResourceRegisterSz( 
        /* [in] */ LPCOLESTR resFileName,
        /* [in] */ LPCOLESTR szID,
        /* [in] */ LPCOLESTR szType) = 0;

    HRESULT STDMETHODCALLTYPE ResourceUnregisterSz( 
        /* [in] */ LPCOLESTR resFileName,
        /* [in] */ LPCOLESTR szID,
        /* [in] */ LPCOLESTR szType) = 0;

    HRESULT STDMETHODCALLTYPE FileRegister( 
        /* [in] */ LPCOLESTR fileName) = 0;

    HRESULT STDMETHODCALLTYPE FileUnregister( 
        /* [in] */ LPCOLESTR fileName) = 0;

    HRESULT STDMETHODCALLTYPE StringRegister( 
        /* [in] */ LPCOLESTR data) = 0;

    HRESULT STDMETHODCALLTYPE StringUnregister( 
        /* [in] */ LPCOLESTR data) = 0;

    HRESULT STDMETHODCALLTYPE ResourceRegister( 
        /* [in] */ LPCOLESTR resFileName,
        /* [in] */ UINT nID,
        /* [in] */ LPCOLESTR szType) = 0;

    HRESULT STDMETHODCALLTYPE ResourceUnregister( 
        /* [in] */ LPCOLESTR resFileName,
        /* [in] */ UINT nID,
        /* [in] */ LPCOLESTR szType) = 0;
};

Figure 8   BandObj.rgs


HKCR
{
    NoRemove CLSID
    {
        ForceRemove %CLSID% = s '%ClassName%'
        {
            InprocServer32 = s '%MODULE%'
            {
                val ThreadingModel = s 'Apartment'
            }
        }
    }
    NoRemove 'Component Categories'
    {
        NoRemove {00021492-0000-0000-C000-000000000046}
        {
            Delete Enum
        }
    }
}

Figure 9   RGSRUN.cpp


////////////////////////////////////////////////////////////////
// Microsoft Systems Journal November 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
//
#define VC_EXTRALEAN    // Exclude rarely-used stuff from Windows headers
#include <afxwin.h>
#include <afxcoll.h>
#include <atlbase.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

void usage()
{
   printf("\n");
   printf("Purpose: Load RGS registrar scripts into the registry\n");
   printf("Usage:   rgsrun [-u -q] files\n");
   printf("         -u = unregister\n");
   printf("         -q = quiet\n");
   printf("         Written 7-99 by Paul Dilascia for MSJ.\n");
   exit(-1);
}

/////////////////
// Instantiate IRegistrar
//
class CTRegistrar : public CComQIPtr<IRegistrar> {
public:
   CTRegistrar() {
      CoCreateInstance(CLSID_Registrar, NULL, CLSCTX_INPROC);
      ASSERT(p);
   }
};

//////////////////
// Console app entry point
//
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
   if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) {
      fprintf(stderr, "Fatal Error: MFC initialization failed");
      return -1;
   }

   if (FAILED(CoInitialize(0))) {
      printf("Error initializing COM\n");
      (-1);

   } else {
      CTRegistrar spReg;
      BOOL unregister=0;
      BOOL quiet=0;
      BOOL any=0;
      for (int i=1; i<argc; i++) {
         if (argv[i][0]=='/' || argv[i][0]=='-') {
            switch (tolower(argv[i][1])) {
            case 'u':
               unregister=1;
               break;
            case 'q':
               quiet=1;
               break;
            default:
               usage();
               break;
            }
         } else {
            USES_CONVERSION;
            LPOLESTR lpo = T2OLE(argv[i]);
            HRESULT hr = unregister ?
               spReg->FileUnregister(lpo) :
               spReg->FileRegister(lpo);
            if (!quiet) {
               printf(FAILED(hr) ?
                  "Error processing %s - ignored\n" : "%s loaded\n",
                  argv[i]);
            }
            any = 1;
         }
      }
      if (!any)
         usage();
   }
   CoUninitialize();
   return 0;
}

Figure 11   TRACEFN Output for MyBands


// Select "Web Search Band" from Toolbars menu
//
DllGetClassObject({4647E383-520B-11D2-A0D0-004033D0645D}, IClassFactory)
CTComDll::OnGetClassObject
DllGetClassObject returns S_OK
CBandObj(011152F0)::CBandObj
CBandObj(011152F0)::QueryInterface(IPersistStreamInit), returns E_NOINTERFACE, 
    *ppv=00000000, count=1
CBandObj(011152F0)::QueryInterface(IDeskBand), returns S_OK, *ppv=01115330, 
    count=2
CBandObj(011152F0)::QueryInterface({EA5F2D61-E008-11CF-99CB-00C04FD64497}), 
    returns E_NOINTERFACE, *ppv=00000000, count=2
CBandObj(011152F0)::QueryInterface(IObjectWithSite), returns S_OK, *ppv=01115334, 
    count=3
CBandObj(011152F0)::IObjectWithSite::SetSite 00431008
CMyDeskBand::OnCreate
CBandObj(011152F0)::OnCreate
CMyDeskBand::OnSize(1131,20)
CBandObj(011152F0)::Release, returns count=2
CBandObj(011152F0)::IOleWindow::GetWindow
CBandObj(011152F0)::IDeskBand::GetBandInfo id=6 mode=0
CBandObj(011152F0)::AddRef, returns count=3
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, 
    count=4
CBandObj(011152F0)::Release, returns count=3
CMyDeskBand::OnSize(0,20)
CBandObj(011152F0)::AddRef, returns count=4
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, 
    count=5
CBandObj(011152F0)::Release, returns count=4
CBandObj(011152F0)::IDockingWindow::ShowDW(1)
CBandObj(011152F0)::AddRef, returns count=5
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, 
    count=6
CBandObj(011152F0)::Release, returns count=5
CMyDeskBand::OnSize(98,20)
CBandObj(011152F0)::Release, returns count=4

// ...running... //

// Right-click for context menu, select "Hotbot"
//
CBandObj(011152F0)::IDeskBand::GetBandInfo id=6 mode=0
CBandObj(011152F0)::QueryInterface(IContextMenu), returns S_OK, *ppv=01115340, count=5
CBandObj(011152F0)::IContextMenu::QueryContextMenu
CTContextMenu::QueryContextMenu(0x65c,i=0,first=4,last=32767,flags=0x0)
CBandObj(011152F0)::AddRef, returns count=6
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, count=7
CBandObj(011152F0)::Release, returns count=6
CBandObj(011152F0)::QueryInterface(IPersist), returns S_OK, *ppv=0111533C, count=7
CBandObj(011152F0)::IPersist::GetClassID
CTPersist::GetClassID
CBandObj(011152F0)::QueryInterface(IOleCommandTarget), returns E_NOINTERFACE, 
    *ppv=00000000, count=7
CBandObj(011152F0)::Release, returns count=6
CBandObj(011152F0)::Release, returns count=5
CBandObj(011152F0)::AddRef, returns count=6
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, count=7
CBandObj(011152F0)::Release, returns count=6
CBandObj(011152F0)::Release, returns count=5
CBandObj(011152F0)::IContextMenu::InvokeCommand(102)
CTContextMenu::InvokeCommand
CBandObj(011152F0)::Release, returns count=4

// Now close
//
CBandObj(011152F0)::IDeskBand::GetBandInfo id=6 mode=0
CBandObj(011152F0)::QueryInterface(IContextMenu), returns S_OK, *ppv=01115340, 
    count=5
CBandObj(011152F0)::IContextMenu::QueryContextMenu
CTContextMenu::QueryContextMenu(0x698,i=0,first=4,last=32767,flags=0x0)
CBandObj(011152F0)::AddRef, returns count=6
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, count=7
CBandObj(011152F0)::Release, returns count=6
CBandObj(011152F0)::QueryInterface(IPersist), returns S_OK, *ppv=0111533C, count=7
CBandObj(011152F0)::IPersist::GetClassID
CTPersist::GetClassID
CBandObj(011152F0)::QueryInterface(IOleCommandTarget), returns E_NOINTERFACE, 
    *ppv=00000000, count=7
CBandObj(011152F0)::Release, returns count=6
CBandObj(011152F0)::Release, returns count=5
CBandObj(011152F0)::AddRef, returns count=6
CBandObj(011152F0)::QueryInterface(IUnknown), returns S_OK, *ppv=01115330, count=7
CBandObj(011152F0)::Release, returns count=6
CBandObj(011152F0)::Release, returns count=5
CBandObj(011152F0)::IDockingWindow::CloseDW
CEditSearch::PostNcDestroy
CBandObj(011152F0)::QueryInterface(IObjectWithSite), returns S_OK, *ppv=01115334, 
    count=6
CBandObj(011152F0)::IObjectWithSite::SetSite 00000000
CBandObj(011152F0)::Release, returns count=5
CBandObj(011152F0)::Release, returns count=4
CBandObj(011152F0)::Release, returns count=3

Figure 14   MyBands.ini


[SearchStrings]
&Altavista=http://www.altavista.com/cgi-bin/query?pg=q&kl=XX&stype=stext&q=MYSEARCH
E&xcite=http://search.excite.com/search.gw?search=MYSEARCH
&Hotbot=http://www.hotbot.com/?MT=MYSEARCH&SM=MC&DV=0&LG=any&DC=10&DE=2&_v=2&OPs=MDRTP
&Infoseek=http://infoseek.go.com/Titles?qt=MYSEARCH&col=WW&sv=IS&lk=noframes
&Lycos=http://www.lycos.com/cgi-bin/pursuit?matchmode=and&cat=lycos&query=MYSEARCH
&Yahoo=http://search.yahoo.com/search?p=MYSEARCH&n=25
AllKeys=&Altavista;E&xcite;&Hotbot;&Infoseek;&Lycos;&Yahoo;
Current=0