5,534,119 members and growing! (17,414 online)
Email Password   helpLost your password?
Languages » C# » General     Beginner

How to attach to Browser Helper Object (BHO) with C# in two minutes

By Jia.C

This article will use screen shots step by step to show beginners how to attach to BHO with C# within only two minutes
C# 1.0, C#, Windows, .NET, Visual Studio, Dev

Posted: 10 Aug 2007
Updated: 10 Aug 2007
Views: 40,970
Bookmarked: 47 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
24 votes for this Article.
Popularity: 5.54 Rating: 4.02 out of 5
2 votes, 8.3%
1
1 vote, 4.2%
2
3 votes, 12.5%
3
1 vote, 4.2%
4
17 votes, 70.8%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

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).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Jia.C


Nerd is cool~

www.horizonideas.com
Occupation: Web Developer
Location: Canada Canada

Other popular C# articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 104 (Total in Forum: 104) (Refresh)FirstPrevNext
Subject  Author Date 
QuestionI am wondering if I can access the cookies of IE by using BHO?memberLee Jenkins16:23 10 Sep '08  
QuestionThe BHO dll is not responsememberLee Jenkins14:05 10 Sep '08  
AnswerOK, I found the reason, you have to enable the third party extension first.memberLee Jenkins14:25 10 Sep '08  
GeneralCan I use BHO to get the ssl/tls certificate information in IE?memberJim_Yang20:33 4 Sep '08  
QuestionEvents not called in IE 7.0memberBruce McHaffie12:13 29 Aug '08  
AnswerRe: Events not called in IE 7.0memberBruce McHaffie16:11 2 Sep '08  
GeneralHi, My BHO is also not being called....memberSwagata223:48 24 Aug '08  
Generalproblem in vista ultimatememberdodiigor14:55 30 Jul '08  
QuestionIn Window Mobile 5.0 BHOmemberSarita Rajput0:50 24 Jul '08  
Generalyoutube javascript methodsmembergal kahana II5:06 20 Jul '08  
GeneralRe: youtube javascript methodsmembergal kahana II22:15 22 Jul '08  
GeneralFor those having problems on non-VS machines (OnDocumentComplete)memberBenJeremy22:28 17 Jul '08  
GeneralHelp in Creating a BHO using C#memberVenkatesh Telugu1:14 14 Jul '08  
GeneralHow do I access favorites clicksmemberMember 451037223:21 7 Jul '08  
GeneralWorking with IE 7 and 8 (Beta)memberKarstenK3:01 16 Jun '08  
QuestionSetSite Method not callingmembermadhu cellulo0:00 16 Jun '08  
QuestionGr8 articlememberNitin Sawant20:28 31 May '08  
QuestionHow about use IDispatch::Invoke()member0:52 29 May '08  
Newsmshtml event handling using C# [modified]memberkantan21:15 7 May '08  
QuestionCan I use BHO to create a dockable form which is like Explorer Band?memberhukid18:18 20 Apr '08  
GeneralRe: Can I use BHO to create a dockable form which is like Explorer Band?memberJia.C8:34 21 Apr '08  
GeneralMy BHO is not being called?memberlgastako12:11 19 Apr '08  
GeneralRe: My BHO is not being called?memberlgastako12:51 19 Apr '08  
GeneralRe: My BHO is not being called?memberJia.C8:30 21 Apr '08  
Generalunregistering DLLmembercachobong20:23 15 Apr '08