본문 바로가기

.NET/C#

c#으로 BHO(Browser Helper Object) 만들기

http://www.codeproject.com/Articles/350432/BHO-Development-using-managed-code
위에서 퍼온 글입니다.

Introduction

Browser Helper Object (BHO) is a plug-in for Internet Explorer (IE). BHO let developers to drive IE. A plug-in is a program which extends the functionality of a browser. It can be used to retrieve information or modify the content of the webpage that is being displayed in a browser window, or it may just be used to provide the user an option to see the day's Stock market status or, weather in a toolbar.

Background 

To start BHO development can be depressing at the very first beginning to learn all those things. As a beginner I want to share my experience to other beginners. Here I am going to explain the simple implementation of BHO.

A Browser Helper Object is a COM object loaded for each IE window. As a browser window is opened, it creates its own copy of the BHO; and, when the window is closed, it destroys its copy of the BHO. You will need a COM DLL which interact with browser. This need to done by implementing the IObjectWithSite in class. We need to use COM interop library to implement COM DLL in our .NET project.

While we are writing in C#, we also need to write the interface IObjectWithSite ourselves. Also, we have to then implement the interface in your BHO. To interact with the HTML document, we will need to add a reference to the Microsoft.mshtml library and to get the DOM or the webpage currently in the browser, we will have to add SHDocVw library as a reference. Also, we will have to add 2 functions which will register (and unregister) our COM component as a BHO with Internet Explorer with the key.

Say Hello to BHO development world: 

Let's create a Hello world project regarding BHO. Start a new C# class library project. I named it as 'HelloBHOWorld'. 

Rename the 'Class1.cs' as 'IObjectWithSite.cs'. 

Add 'using System.Runtime.InteropServices;' to the class. We need to implement the interface 'IObjectWithSite' under this class and we also need to add to function 'GetSite' and 'SetSite'. To know more about this interface, please refer to http://msdn2.microsoft.com/en-us/library/Aa768220.aspx

IObjectWithSite Members

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.

Under the IObjectWithSite.cs, we need to point out the GUID of IE for our program, so it can attach to IE. The code snippet should look like the following,

using System.Runtime.InteropServices;
namespace HelloBHOWorld
{
    //GUID reference of IF
    [
    ComVisible(true),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
    Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")
    ]
    //Declaration of the interface
    publicinterfaceIObjectWithSite
    {
        [PreserveSig]
        int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site);
        [PreserveSig]
        int GetSite(refGuid guid, outIntPtr ppvSite);
    }
}

We have done with IObjectWithSite.cs. New we need to add another class file named BHO.cs. Add a class BHO there. As we mentioned before we need to have two references, SHDocVw.dll and MSHTML.dll. SHDocVw is Microsoft Shell Doc Object and Control Library. MSHTML is the 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. To know more, please refer to: http://msdn2.microsoft.com/en-us/library/bb498651.aspx

Let's add them,


We are going to use messagebox to display information, so we need to add another reference,

We need to add the following reference under BHO.cs file,

using SHDocVw;
using mshtml;
using System.IO;
using Microsoft.Win32;
using System.Runtime.InteropServices;

We will need to implement the inerface on BHO class, later we will define the two method.

We need to assign a GUID for our own program under BHO.cs. We can use the System.Guid.NewGuid() method to get a new key (I have a small tool to generate GUID). And also we will add two variables into the class, WebBrowser and HTMLDocument.

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

public static string BHO_KEY_NAME = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects";
[ComRegisterFunction]
public static void RegisterBHO(Type type)
{
    RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHO_KEY_NAME, true);
    if (registryKey == null)
        registryKey = Registry.LocalMachine.CreateSubKey(BHO_KEY_NAME);
    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(BHO_KEY_NAME, true);
    string guid = type.GUID.ToString("B");
    if (registryKey != null)
    registryKey.DeleteSubKey(guid, false);
}

Here we will use OnBeforeNavigate() method to retrieve some information from browser. 'OnBeforeNavigate' invokes an event before navigation occurs on the web browser. To know more please refer, http://msdn.microsoft.com/en-us/library/2chzz53b.aspx

So next we write the method body of OnBeforeNavigate method and define the 'SetSite' and GetSite' method. On 'SetSite' method we write the event handler for OnBeforeNavigate function.

public void OnBeforeNavigate2(object pDisp, ref object URL, refobject Flags, 
       ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
{
}
#region IObjectWithSite Members
public int SetSite(object site)
{
    if (site != null)
    {
        webBrowser = (WebBrowser)site;
        webBrowser.BeforeNavigate2 += new
        DWebBrowserEvents2_BeforeNavigate2EventHandler(this.OnBeforeNavigate2);
    }
    else
    {
        webBrowser.BeforeNavigate2 -= new
        DWebBrowserEvents2_BeforeNavigate2EventHandler(this.OnBeforeNavigate2);
        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;
}
#endregion

For example we write some code for method 'OnBeforeNavigate2'. This code will track the input field of the site and show input fields name and value.

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;
    System.Windows.Forms.MessageBox.Show("URL to redirect: " + URL.ToString());
    foreach (IHTMLInputElement tempElement in document.getElementsByTagName("INPUT"))
    {
        System.Windows.Forms.MessageBox.Show(tempElement.name + " = " + tempElement.value);
    }
}

Register and unregister BHO:

To register/unregister BHO we use 'RegAsm.exe' and write to bat file 'registercom.bat' and 'unregisterall.bat':

REM register for com so we can test the register/unregister functions while debugging
regasm.exe /codebase "HelloBHOWorld.dll"
pause
REM unregister HelloBHOWorld.dll for COM
regasm.exe /unregister "HelloBHOWorld.dll"
pause

Run the file 'registercom.bat'

Now open IE browser and go to 'Tools'>'Manage Add-ons…' You should see your BHO is on the list

Now browse any site (google.com), input text on the box and click button. You should see,

So this can be your first add-in for IE. This is just the beginning, long way to go for writing a professional BHO. Let's hope for the best.

Please don't forget to drop your comments……………..