I have been dabbling with BHO’s for some time, way back with VB6, then tried in .NET, and with C++ as well. There are so many cool things you can do with them. Anyways, most of the documentation out there is sparse and old. I told myself the next time I have to make one, I am going to document it. Well, here it is in all its glory. Sorry if the code formatting is wacked, but you get the picture. I don’t claim to be an expert, but this should work đŸ™‚
just in case, I uploaded it in txt format for better reading here
How to Create a Browser Helper Object in Visual Studio 2005 with C++
———————————————————————
1) Open Visual Studio 2005
2) File->New->Project
3) Visual C++
4) ATL
5) ATL Project
6) Name is whatever you want for this example I use “Company.Browser.Helper” without the quotes
7) The ATL Project Wizard Screen will appear, Hit Finish
8) Visual Studio will load up your project.
9) Right Click on The Company.Browser.Helper project, Add->Class
10) select ATL Simple Object, and click the Add button
11) fill in the ShortName – “BrowserHelper” without the quotes, the rest of the fields should fill in, hit next
12) IMPORTANT: Under Support: Check all boxes (ISupportErrorInfo, Connection points, IObjectWithSite (IE object Support)
13) Click Finish
Now on to the better stuff,
————————————————————–
In visual studio, Solution Explorer, Resource Files, you will see BrowserHelper.rgs, open it and add this to the bottom
(replace the GUID with the GUID that you see at the top of the file like CLSID = s ‘{GUID}’) in the other script code
This will register the BHO with IE when the DLL gets registered
HKLM
{
SOFTWARE
{
Microsoft
{
Windows
{
CurrentVersion
{
Explorer
{
'Browser Helper Objects'
{
{GUID}
}
}
}
}
}
}
}
above where it says ‘Browser Helper’ – you can change those names to be more descriptive, that will show in IE add on manager
————————————————————–
————————————————————–
// in the Header Files -> stdafx.h, the bottom part of the file should look like this:
#include "resource.h"
#include
#include
#include
#define CAtlString CString
using namespace ATL;
--------------------------------------------------------------
//in Source Files-> BrowserHelper.cpp you need to include
#include
--------------------------------------------------------------
Then you need to implement methods listed here. You really shouldnt have to modify these
// this should be created by the wizard
STDMETHODIMP CBrowserHelper::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IBrowserHelper
};
for (int i=0; i FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr))
{
return hr;
}
// Subscribe the event handlers to the container
hr = spCP->Advise(reinterpret_cast(this), &m_dwCookie);
return hr;
}
STDMETHODIMP CBrowserHelper::IEUnAdvise(void)
{
HRESULT hr;
CComPtr spCP;
// Receives the connection point for WebBrowser events
hr = m_CPCptr->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr))
{
return hr;
}
// Unsubscribe the event handlers to the container
hr = spCP->Unadvise(m_dwCookie);
return hr;
}
STDMETHODIMP CBrowserHelper::IEQuit(void)
{
return IEUnAdvise();
}
------------------------------------------------------------------------------------------
//then you need to implement the invoke method, as you can see i just care about the IEBeforeNaviate2() method
//so i commented the rest of the case statements out but left them in case i need them
STDMETHODIMP CBrowserHelper::Invoke(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pvarResult,
EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
if (!pDispParams)
{
return E_INVALIDARG;
}
switch(dispidMember)
{
case DISPID_BEFORENAVIGATE2: // Before Naigation
IEBeforeNavigate2(pDispParams);
break;
// case DISPID_COMMANDSTATECHANGE:// Command state change
// IECommandStateChange(pDispParams);
//break;
// case DISPID_DOCUMENTCOMPLETE: // Document completed
// IEDocumentComplete(pDispParams);
//break;
// case DISPID_DOWNLOADCOMPLETE: // Download completed
// IEDownloadComplete(pDispParams);
//break;
// case DISPID_NAVIGATECOMPLETE2: // Navigation completed
// IENavigateComplete2(pDispParams);
//break;
// case DISPID_NEWWINDOW2: // Open a new window
// IENewWindow2(pDispParams);
//break;
// case DISPID_PROGRESSCHANGE: // The progress status change
// IEProgressChange(pDispParams);
//break;
// case DISPID_STATUSTEXTCHANGE: // The status bar text change
// IEStatusTextChange(pDispParams);
//break;
// case DISPID_TITLECHANGE: // Title change
// IETitleChange(pDispParams);
//break;
// case DISPID_ONQUIT: // Quit
// IEQuit();
//break;
}
return S_OK;
}
------------------------------------------------------------------------------------------
//then implement BeforeNavigate2 - you can see the relevant code between the ***** that will
//check if IE is on google and redirect them to yahoo. You can add more code here like checking registry for a key,
//launching a process, etc, etc
void CBrowserHelper::IEBeforeNavigate2(DISPPARAMS* pDispParams)
{
CComQIPtr WebBrowser2Ptr;
CAtlString url;
VARIANT_BOOL* ptrBoolCancel;
VARTYPE vt;
// Check the type of IWebBrowser2
vt = pDispParams->rgvarg[6].vt;
if(vt == 0x0009)
{
WebBrowser2Ptr = pDispParams->rgvarg[6].pdispVal;
}
else
{
// Wrong type, return.
return;
}
// Check the first parameter type is VT_BYREF|VT_BOOL or not
vt = pDispParams->rgvarg[0].vt;
if(vt == 0x400B)
{
ptrBoolCancel = pDispParams->rgvarg[0].pboolVal;
}
else
{
// Wrong type, return.
return;
}
// Check the URL parameter type
vt = pDispParams->rgvarg[5].vt;
if(vt == 0x400C)
{
USES_CONVERSION;
url = OLE2T(pDispParams->rgvarg[5].pvarVal->bstrVal);
}
else
{
// Wrong type, return.
return;
}
// *********************************************************
// check for a given URL
if(url == _T("http://www.google.com/") || url == _T("http://www.google.com"))
{
BSTR newUrl = _T("http://www.yahoo.com/");
*ptrBoolCancel = TRUE;
WebBrowser2Ptr->Navigate(newUrl,NULL,NULL,NULL,NULL);
}
// ********************************************************
}
----------------------------
//you will need to wire these up in your header file, so in HEader Files->BrowserHelper.h it would look like this
----------------------------
// BrowserHelper.h : Declaration of the CBrowserHelper
#pragma once
#include "resource.h" // main symbols
#include "ExDisp.h"
#include "CompanyBrowserHelper.h"
#include "_IBrowserHelperEvents_CP.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif
// CBrowserHelper
class ATL_NO_VTABLE CBrowserHelper :
public CComObjectRootEx,
public CComCoClass,
public ISupportErrorInfo,
public IConnectionPointContainerImpl,
public CProxy_IBrowserHelperEvents,
public IObjectWithSiteImpl,
public IDispatchImpl
{
public:
CBrowserHelper()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_BROWSERHELPER)
BEGIN_COM_MAP(CBrowserHelper)
COM_INTERFACE_ENTRY(IBrowserHelper)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CBrowserHelper)
CONNECTION_POINT_ENTRY(__uuidof(_IBrowserHelperEvents))
END_CONNECTION_POINT_MAP()
public:
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
//
// 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);
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
private:
CComQIPtr m_CPCptr;
DWORD m_dwCookie; // Connection Token - used for
// Advise and Unadvise
enum ConnectType { Advise, Unadvise }; // What to do when managing
// the connection
STDMETHOD(IEAdvise)(void);
STDMETHOD(IEUnAdvise)(void);
STDMETHOD(IEQuit)(void);
void IEBeforeNavigate2(DISPPARAMS* pDispParams);
};
OBJECT_ENTRY_AUTO(__uuidof(BrowserHelper), CBrowserHelper)
----------------------------
And Finally,
To Test:
you shouldnt have to create or modify any more code, if you build it, you should get a dll
then to register with the system you need to call
regsvr32 DllName.dll
now open a browser and goto http://www.google.com and it will redirect to yahoo!
and if you look at the loaded add-ons, it should be in the list
close all your browsers
and to unregister
regsvr32 /u DllName.dll
open a browser and try google, it should work as normal
-------------------------------------------------------------
15 replies on “VS2005 – Browser Helper Object (BHO) Tutorial”
Hey.. we have a BHO that will open up a client file, and direct them to the appropriate web page. My question is, if the BHO isn’t installed yet, can you make it take you to the download software page?
LikeLike
no, you would need the BHO installed first to make the BHO do any sort of redirecting
LikeLike
Hi,
Mayby you know how to get the pointer to new IE window when it’s created (in case of DISPID_NEWWINDOW2)? I think it’s something like WebBrowser2Ptr = pDispParams->rgvarg[6].pdispVal, but it does not work.
LikeLike
Hey,
Do you know how to make a BHO in vb.net? I’ve searched anywhere and can’t find any information on it.
LikeLike
well, the first BHO’s I made way back in the day were in VB 6. You can make a BHO in .NET as well…
http://www.15seconds.com/issue/040331.htm
that example is in C#, but you should be able convert it over to VB.net pretty easily
LikeLike
Great sample. Exactly what I need to get started. I can’t get the project built though due to an error about the non-existance of the ATL namespace.
There are a number of lines with just “#include” and no filename specified. Is there something missing?
LikeLike
Hi Steve – everyone should definitely follow the text version. Once I did that, it all works fine. Thanks for the lesson.
LikeLike
Ellie, did you get a BHO project working with VB yet, if so are you willing to share an example? I’m clueless in how to do it with VB…
LikeLike
where do the methods go?
LikeLike
Brilliant example and presentation – everything works as promised. After loads of struggle in MSDN jungle, it’s like heaven. đŸ˜‰
LikeLike
ExDisp.h
LikeLike
Great example. How would you go about using the BHO to interact with the IE GUI (say, add an image to a toolbar)?
Conrad
LikeLike
Hi,
I try this example but I have a problem. It don’t call setSite.. must it call automatically or i must call it somewhere??
thank you very much for your answer,
Valerio
LikeLike
Hi;
When i try to compile this sample i got these errors. How can i manage i?
Error 1 error C2955: ‘ATL::CComObjectRootEx’ : use of class template requires template argument list
Error 2 error C2955: ‘ATL::CComCoClass’ : use of class template requires template argument list
Error 3 error C2955: ‘ATL::IConnectionPointContainerImpl’ : use of class template requires template argument list
Error 4 error C2504: ‘CProxy_IBrowserHelperEvents’ : base class undefined
Error 5 error C2955: ‘ATL::IObjectWithSiteImpl’ : use of class template requires template argument list
Error 6 error C2955: ‘ATL::IDispatchImpl’ : use of class template requires template argument list
Error 7 fatal error C1903: unable to recover from previous error(s); stopping compilation
LikeLike
Yes, some code is missing.
Included header is also:
#include , not maybe it’s now obselete.
And fix the errors ‘use of class template requires template argument list’ by adding right arguments:
CComQIPtr WebBrowser2Ptr;
CComPtr spCP;
CComQIPtr m_CPCptr;
Reference: http://msdn.microsoft.com/en-us/library/Bb250436.aspx#bho_writing
LikeLike