Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Microsoft provided Browser Helper Object (BHO) to let developers "drive" Internet Explorer. The first BHO was introduced in 1997 with IE 4.0. I have been writing programs on BHO for months. It could be quite depressing at the very first beginning to learn all those things. Hereby, I am writing this article to help beginners like me get familiar with BHO as soon as possible.

Background

My personal interest is actually C++. C++ programs can be a lot less memory-consuming than C# programs. But C# does provide better service on BHO comparing to C++. My first BHO program was written in C++. It took me quite a while to figure out how to handle BHO under V C++. But C# only takes me few minutes. Meanwhile, C# has lots of pleasant designs such as foreach and type conversion.

Process

To set up a BHO Hello World Project, Lets first start a C# Class Library, as BHO is written in .dll attached to IE. You dont need a Visual Studio 2005, C# express is totally enough.




After we have this empty project, let's add one folder named BHO and an empty .csfile into the folder.


The first file has to been named IObjectWithSite to notify that this is a BHO project. To know more about this interface, please refer to http://msdn2.microsoft.com/en-us/library/Aa768220.aspx

We also need to add two functions

GetSite: Gets the last site set with IObjectWithSite::SetSite. If there is no known site, the object returns a failure code.

SetSite: Provides the site's IUnknown pointer to the object.

        public interface IObjectWithSite
{
            [PreserveSig]
            int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site);
            [PreserveSig]
            int GetSite(ref Guid guid, out IntPtr ppvSite);
        } 

Don't forget

using System.Runtime.InteropServices;  

Add another .cs file named BHO.cs

Add a class called BHO in the newly added file(BHO.cs) . The class contains the interface IObjectWithSite

    class BHO:IObjectWithSite
  

To use BHO we need to have two references, SHDocVw.dll and MSHTML.dll.You can find them at Windows\System32 folder

SHDocVw is Microsoft Shell Doc Object and Control Library

MSHTML is: All interfaces for accessing the Dynamic HTML (DHTML) Object Model are based on IDispatch and are the basis of access to the object model that is also used by scripts. http://msdn2.microsoft.com/en-us/library/bb498651.aspx

using SHDocVw;
using mshtml;
using System.Runtime.InteropServices;   
namespace BHO_HelloWorld
{ 
class BHO:IObjectWithSite
{}

}
    

have "using SHDocVw" is not enough, you need to add references to the project.

Add SHDocVw

Later we are going to use MessageBox, we also need to add Windows Form reference

Now under BHO.cs:

we add two variables into the class, WebBrowser and HTMLDocument. Just like their name, you could easily figure out what do they do.

Besides the two methods we defined in the IObjectWithSite interface, we also need to add OnDocumentComplete. You can name the function anything you want as long as the parameters are the same as what's defined in CDHtmlDialog class. Later you need to carfully attach to an EventHandler. For the consistency of code, we name it OnDocumentComplete. OnDocumentComplete is a function of CDHtmlDialog Class http://msdn2.microsoft.com/en-us/library/8bed8k60(VS.80).aspx . It will be triggered if the HTMLDocument downloading is complete, in other words, when your page is loaded. You can also use Navigate() or OnBeforeNavigate(). Please refer to http://msdn2.microsoft.com/en-us/library/8k5z3ekh(VS.80).aspx to find out what you need exactly.

class BHO: IObjectWithSite
{ 
 WebBrowser webBrowser;
HTMLDocument document;
publiv void OnDocumentComplete(object pDisp, ref object URL)
{
 
} 
public void SetSite(object site)
{
}
 
public int GetSite(ref Guid guid, out IntPtr ppvSite)
{
 
}

}

Under the IObjectWithSite.cs:

you need to point out the GUID of IE for thei program, so it can attach to IE.

    [
    ComVisible(true),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
    Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")
    ]

        public interface IObjectWithSite
        {
            [PreserveSig]
            int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site);
            [PreserveSig]
            int GetSite(ref Guid guid, out IntPtr ppvSite);
        }

Also, you need to assian a GUID for your own program under BHO.cs. You can use System.Guid.NewGuid() method to get one, which is really neat comparing to C++.

    [
    ComVisible(true),
    Guid("8a194578-81ea-4850-9911-13ba2d71efbd"),
    ClassInterface(ClassInterfaceType.None)
    ]
  

You cannot just leave SetSite and GetSite blank. fill them in. This step is to tell IE that the DocumentCompletent Event is attached to OnDocumentComplete in our program.

    public int SetSite(object site)
        {

            if (site != null)
            {
                webBrowser = (WebBrowser)site;
                webBrowser.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
            }
            else
            {
                webBrowser.DocumentComplete -= new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
                webBrowser = null;
            }

            return 0;

        }

        public int GetSite(ref Guid guid, out IntPtr ppvSite)
        {
            IntPtr punk = Marshal.GetIUnknownForObject(webBrowser);
            int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite);
            Marshal.Release(punk);

            return hr;
        }
    

Add one more reference

using Microsoft.Win32;     

Under BHO.cs we need to write two functions for register/unregister of this DLL.

  public static string BHOKEYNAME = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects";

        [ComRegisterFunction]
        public static void RegisterBHO(Type type)
        {
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true);

            if (registryKey == null)
                registryKey = Registry.LocalMachine.CreateSubKey(BHOKEYNAME);

            string guid = type.GUID.ToString("B");
            RegistryKey ourKey = registryKey.OpenSubKey(guid);

            if (ourKey == null)
                ourKey = registryKey.CreateSubKey(guid);

            ourKey.SetValue("Alright", 1);
            registryKey.Close();
            ourKey.Close();
        }

        [ComUnregisterFunction]
        public static void UnregisterBHO(Type type)
        {
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true);
            string guid = type.GUID.ToString("B");

            if (registryKey != null)
                registryKey.DeleteSubKey(guid, false);
        }
    

Now compile, under your release folder, you will find the .dll of your own project.

Then, use regasm /codebase "BHO HelloWorld.dll" to register our dll. We got a problem here. The REGASM told me it's not registerd. WHY?

Because we didn't set the BHO class as public. That's why.

public class BHO:IObjectWiteSite

now, do it again. It's successful.

open your registry. Find out Browser Helper Object under LOCAL_MACHINE->SOFTWARE->MICROSOFT->WINDOWS->EXPLORER

So, now program has been officially attached to your BHO. We need to fillin the OnDocumentComplete function. It's really neat to use C#'s foreach loop rather than for loop in C++. So you won't need to care about the indexer. We will also see the type conversion is quite easy. This is an example on we want to find out the NAME attributes of an IHTMLInputElement.

An IHTMLInputElement is an Input element on HTML Page.

If the IHTMLInputElement does not have name attributes, we will fetch the ID attribute. Then pop up the value.

            public void OnDocumentComplete(object pDisp, ref object URL)
        {
          
                document = (HTMLDocument)webBrowser.Document;
             
                foreach (IHTMLInputElement tempElement in document.getElementsByTagName("INPUT"))
                {
                    System.Windows.Forms.MessageBox.Show(
                        tempElement.name!=null?tempElement.name:"it sucks, no name, try id"+((IHTMLElement)tempElement).id
                        );
                }
        }
    

There you go, see?

Now, let's try using BeforeNavigate()2.

As we can see, there are BeforeNavigate and BeforeNavigate2(). We go for the latter one. If you are interested, you can use the first one.

Add the function prototype.

 public void OnBeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) 

Set up the hook.

    public int SetSite(object site)
        {

            if (site != null)
            {
                webBrowser = (WebBrowser)site;
                webBrowser.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
                webBrowser.BeforeNavigate2+=new DWebBrowserEvents2_BeforeNavigate2EventHandler(this.OnBeforeNavigate2);
            }
            else
            {
                webBrowser.DocumentComplete -= new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
                webBrowser.BeforeNavigate2 -= new DWebBrowserEvents2_BeforeNavigate2EventHandler(this.OnBeforeNavigate2);
                webBrowser = null;
            }

            return 0;

        }
    

Now, we want to steal the passwords on an Input Password element

    public void OnBeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
        {
            document = (HTMLDocument)webBrowser.Document;

            foreach(IHTMLInputElement tempElement in document.getElementsByTagName("INPUT"))
            {
            if(tempElement.type.ToLower()=="password")
            {
            
                System.Windows.Forms.MessageBox.Show(tempElement.value);
            }
            
            }
        
        }
    

See, how easily, you can get it.


Conclusion

In conclusion, its really easy to handle BHO with C#. Thats why many there are so many IE add-ons. I hope these are useful to you. To save your time, you can use the project template I made. Download it and put it under your Visual Studio 2005\Templates\ProjectTemplates folder (its usually under My Document).

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralBHO to display area scrolled
codeprojectuser2010
0:27 11 Jan '10  
Hi,
I am creating a BHO which has to be called on the scroll_complete event and should display the number of pixels scrolled. Please provide help to build such BHO.

Regards,
NewUser. Smile
GeneralRegarding your BHO
Vishal_007
8:00 30 Nov '09  
Thanks for Reply.
But you have not answered that why your BHO is not working.

I really want to develop BHO for my website. so i think you can
help me. you also can mail me at vishprog@yahoo.co.in.


Thanks and Regards,
Jani Vishal
GeneralHow get instance of tollbar
ramveers
23:24 17 Sep '09  
HI
How can i get instance of toolbar. I want single instance of IE toolbar on all tabs.
Can i do it by using BHO.
GeneralHow can I call function in C# BHO through Javascript
hjzhu
21:58 1 Sep '09  
thanks
GeneralHow can I accecc c# bho method from javascript
hjzhu
21:56 31 Aug '09  
Would you give me a sample,thanks
Generalhow link the my program with email by c# ?
salemmohamed
19:59 9 Aug '09  
this is my program please help me

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;

namespace lastone
{

public partial class Form1 : Form
{
public Form1()
{

InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'dddDataSet3.Table1' table. You can move, or remove it, as needed.
this.table1TableAdapter.Fill(this.dddDataSet3.Table1);


}

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{

}

private void groupBox1_Enter(object sender, EventArgs e)
{

}

private void button1_Click(object sender, EventArgs e)
{
this.table1TableAdapter.Update(dddDataSet3);
MessageBox.Show("Updated ,,,successfully");
}

private void button2_Click(object sender, EventArgs e)
{


string user = this.comboBox1.SelectedItem.ToString();
string Type_Reqt = this.comboBox5.SelectedItem.ToString();
string Description = this.richTextBox1.Text.ToString();
string status = this.comboBox4.SelectedItem.ToString();
string Date = this.textBox1.Text.ToString();
{
OleDbConnection con = new OleDbConnection("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = D:\\ddd.mdb");
con.Open();
MessageBox.Show("database connected");
string command1 = string.Format("Insert into Table1([user],[Type_Reqt],[Description],[status],[Date]) VALUES('" + user + "','" + Type_Reqt + "','" + Description + "','" + status + "','" + Date + "');");

OleDbCommand command = new OleDbCommand(command1, con);
command.Connection = con;
command.CommandText = command1;
MessageBox.Show(command.CommandText.ToString());
command.ExecuteNonQuery();
con.Close();
}
}
}
}
GeneralException from HRESULT: 0x80040200
Boaz Feldbaum
22:55 20 Jul '09  
When trying to unregister events, I get a COMException with message "Exception from HRESULT: 0x80040200"

The following line produces the exception:

m_webBrowser.BeforeNavigate2 -= new DWebBrowserEvents2_BeforeNavigate2EventHandler(OnBeforeNavigate2);

How to avoid it?

Thanks a lot in advance,
Boaz.
Generaldeployment
thebrim
5:03 20 Jul '09  
hi,

how to deploy an BHO like this on other machines?
do I need to deploy the Interop.SHDocVw.dll?

could you provide an WiX script? I cant find a solution.

nix

Generaldeployment
thebrim
5:34 13 Jul '09  
Hi.

I wrote a plugin and now I want to build an Installer without using the regasm command and self-registration.

How to do that?

I use the Windows Installer Xml Compiler

nix

GeneralRegarding your BHO
Member 2538780
10:04 22 Jun '09  
Its very nice article and i have installed it in my browser and i can see the mscoree.dll but it is not working and now i want to unregister the dll and try to reinstall but i got error while unregister the dll and i got error as under

RegAsm : error RA0000 : Unable to locate input assembly 'Classlibrary1.dll'
or one of its dependencies.

Thanks and Regards,

Vishal Jani
GeneralRe: Regarding your BHO
elbertlev
21:42 10 Aug '09  
THERE IS NO REASON TO RENSTALL, BUT OF YOU WANT JUST DELETE THE REGISTRY KEY AND "UNINSTALL" IS DONE. THIS IS EXACTLY WHAT UNREGISTER IS DOING.
GeneralRe: Regarding your BHO
Vishal_007
2:10 30 Nov '09  
Thanks for Reply.
But you have not answered that why your BHO is not working.

I really want to develop BHO for my website. so i think you can
help me. you also can mail me at vishprog@yahoo.co.in.


Thanks and Regards,
Jani Vishal
QuestionFirefox
vanila23
8:22 19 Jun '09  
Hi, I wonder if I can use this code for Mozilla Firefox instead of Internet Explorer or what kind of modification I should do??
Thnx
QuestionControling the execution of JScript Code in IE
asahin9
14:57 10 Jun '09  
Hi;

I want to write an Internet Explorer extension which will basically check the JavaScript code before it is executed (in runtime). Is there any way to do this?

Thanks
AnswerRe: Controling the execution of JScript Code in IE
AlexTiffy
20:05 11 Nov '09  
:(
GeneralCorrections on article.
xzz0195
5:23 17 Mar '09  
Using C# express, I followed your article and wanted to post corrections needed for the next person.

BHO class needs these references:
using SHDocVw;
using mshtml;
using Microsoft.Win32; <-----Needed for RegistryKey references.
using System.Runtime.InteropServices;
using System; <-----This one must be there to avoid Intptr and Guid compile errors.


Note: Read the section on compiler attributes carefully. The interface doesn't take all of the same attributes as the BHO class.

BHO takes these attrs:
[
ComVisible(true),
Guid("8a194578-81ea-4850-9911-13ba2d71efbd"),
ClassInterface(ClassInterfaceType.None)
]
The Interface takes these:
[
ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")
]


Finally, this solution appears to be good when you want to interface to the native IExplorer browser. However, virtually all of this function is available for the webBrowser object which you can embed into your own form. The webBrowser object is much easier to use (IMO).

Thanks for the post, hope this helps...
GeneralHow to solve delay in display of replaced text on a web page? How to reduce CPU usage which is caused due to 'foreach loop'?
svt gdwl
19:41 29 Jan '09  
I had created a small application from the article http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx?fid=447248&df=90&mp p=25&noise=3&sort=Position&view=Quick&fr=51&select=2421069
But while the control is in "foreach loop", the CPU usage increases near about 80-90%. I just want to reduce that CPU usage.


The other thing is if I try to manipulate the web page text, the original text is visible to user for a fraction of second, and then the replaced text is visible to user. I don't want that original text is visible to user. I just want to replace the original text of a web page on the fly, for the I am using DWebBrowserEvents2_ProgressChangeEventHandler.

In the foreach loop I was identifying the tagname and replacing the innertext of tag element.
I want the replaced text should be seen directly by the user. But there was some delay in displaying the replaced text. i.e., initially for a fraction of second the original text is visible to user before the replaced text.

How can I avoid these two problems and the output should be...

1. User should be seen directly the replaced text but not the original text of a web page.
2. The CPU usage should be reduced which is caused because of "foreach loop".


As well as I was trying to identify individual tag elements using
http://www.codeproject.com/KB/shell/enum_selected_elements.aspx?
in which IMarkupServices interface is used. Here also same problem occurs. There is some delay in displaying the replaced text on the web page.


But the main problems are:
1. Delay in display of replaced text on a web page when it is visible to the user
2. The CPU usage is high which is caused because of "foreach loop".

I manipulated by innertext property of HTML tag elements in a foreach loop.
This has been developed from
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx?fid=447248&df=90&mp p=25&noise=3&sort=Position&view=Quick&fr=51&select=2421069



How can i solve this.........

Any suggestions would have been appreciated.

I had spent so much time on these but are of no use.



I tried all these links but output is samea nd my problems can't be avoided.

http://social.msdn.microsoft.com/Forums/en-US/Offtopic/thread/1c835fad-66c0-46ba-b499-3ba7090bd660/

http://www.eggheadcafe.com/community/aspnet/2/10073309/how-to-reduce-cpu-usage-w.aspx
GeneralRe: How to solve delay in display of replaced text on a web page? How to reduce CPU usage which is caused due to 'foreach loop'?
HUMPPAAA!
6:11 26 Mar '09  
Hi,
I have the same problem like you with that 1 second delay.
Have You solved that in the meantime?

greetings
~me
GeneralIf page opens in a iframe then how to access the contents/tags of iframe
harshkapoors
5:44 20 Jan '09  
Hi,

I have read this page and impllemented the functionality but i couldn't got the right solution. i think i couldn't implemented it in right place.

Actually i am working with BHO, that works to get the URL of the site and access the contents/tags of iframe and for this i register it firstly.

public void OnDocumentComplete(object pDisp, ref object URL)
{
foreach (HTMLIFrame tempElement in document.getElementsByTagName ("iframe"))
{
System.Windows.Forms.MessageBox.Show(URL.ToString());
}
}

public int SetSite(object site)
{

if (site != null)
{
webBrowser = (WebBrowser)site;
webBrowser.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
}
else
{
webBrowser.DocumentComplete +=new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
webBrowser = null;
}
return 0;
}

from this i am fetching the URL of the iframe but how can i access the tags of iframe?

and where i have to implement it?

Please give me a solution.

Thanx in advance.

Regards
Harsh
GeneralRe: If page opens in a iframe then how to access the contents/tags of iframe
svt gdwl
19:45 20 Jan '09  
you can access in two ways:

1. tempElem.contentWindow.document.innerHTML

2. document.frames.item(ref index)
Generalmscoree.dll
tr4nc3
20:44 13 Jan '09  
The BHO shows up in the browser as mscoree.dll even though the registered DLL is TestBHO.dll or something like that. Is there someway to change the name of the DLL to something that I choose? Where is the setting located to name the registered control as mscoree.dll?

Thanks.
GeneralHow to reduce CPU usage when the dll is registered?
abhi11shukla
22:35 6 Jan '09  
Hi,
Great article.
I just downloaded the Source code, and build it and registered.

After registering the dll, if I open IE, the CPU usage is shown as 40-50% and sometimes even 100%.
Even when I try to build the solution provided, VCSExpress.exe also consumes 100% CPU usage. How to reduce this?
Generalhow to debug?
Maverickcool
3:10 4 Jan '09  
i'm having troubles to debug this
what do I need to do in order to debug?
GeneralRe: how to debug?
Boaz Feldbaum
22:46 20 Jul '09  
Add Debugger.Launch():

public int SetSite(object site)
{
if (site != null)
{
Debugger.Launch(); // <==========


using System.Diagnostics;
GeneralHow to catch when user clicks on a link in internet explorer?
jan1503
0:31 12 Dec '08  
Hi!

I want to catch when a user clicks on a link on a webpage and send the clicked link (it's url) to my program. Altering the http-protocol-handler does not work [^]

Then my program analyzes the url and will pass it to the same or a new IE instance or, if it's on a special "black-list", throws a messagebox.

Thanks,
Jan


Last Updated 10 Aug 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010