Click here to Skip to main content
Click here to Skip to main content

Issues faced while extending IE with Band Objects using .NET and Windows Forms

, 13 Aug 2007
Rate this:
Please Sign up or sign in to vote.

Download - 170.8 KB


Here, i would share some of the issues faced while developing the IE toolbar by extending a band object. I would recommend the following readings, if you are new to band objects before moving on further:

1. Creating Custom Explorer Bars, Tool Bands, and Desk Bands: It gives an idea of what exactly the bandobjects are.

2. Extending Explorer with Band Objects using .NET and Windows Forms By Pavel Zolnikov: It's a nice article, i would say. if you are new to IE extension development this article can help you a lot.

3. Band Objects - .NET 2.0 Redux By cambo1982: It is all about migrating your custom IE toolbar code developed in visual studio 2003 to 2005.

About the code

The sample toolbar(does have very basic UI) incorporates almost all the solutions discussed above. To Run the sample, build the code in the release mode to get msi and Run the msi to install the toolbar.

1. BandObjectLib

I have used Pavel Zolnikov's Bandobject library in the code and did following minor additions to it as well.
i) Added DBIMF enum and used in DESKBANDINFO struct (defined in ComInterop.cs)
ii) Modified GetBandInfo() in BandObject.cs
iii) Modified TranslateAcceleratorIO() in BandObject.cs

2. SearchBar

SearchBar is the toolbar's dll that contains
i). Toolbar class that extends BandObject defined in BandobjectLib (Toolbar.cs)
ii). A BHO Class (InitToolbarBHO.cs)
iii). An installer class that defines custom actions (InstallerClass.cs)
iv). Logger class (Logger.cs)
v). External config file (App.config)

3. ToolbarInstaller

It is a setup project that generates msi installer.

Issues and their solutions:

#1. Toolbar is not selected at IE startup by default like Google and Yahoo toolbars

It is required to select the toolbar from IE Tools->Toolbars menu before you can view it and once you selected the toolbar and it is visible, if you switch to another tab it needs to select the toolbar again.

The solution is to implement a BHO that would display the custom toolbar as soon as the IE browser starts. A Browser Helper Object (BHO) is a DLL module designed as a plugin for Microsoft's Internet Explorer web browser to provide added functionality(This definition is from wikipedia). A Browser Helper Object is loaded when the main window of the browser is about to be displayed and is unloaded when that window is destroyed. If you open more copies of the browser window, more instances of the BHO will be created.

A BHO is a COM object, so we need to add attributes to the class definition. One attribute is a GUID that should be unique. Once you generate this GUID, you can use that value forever for this one class. You can use Create Guid tool(guidgen.exe) from visual studio Tools menu to create a new GUID. BHO must implement IObjectWithSite as well.

Here an example of implementing the BHO.

I. Adding com attributes to the BHO class

   public class ShowToolbarBHO : IObjectWithSite

II. Implementing IObjectWithSite Members

IObjectWithSite interface has two methods SetSite and GetSite. The SetSite method is invoked when the BHO is instantiated and when it is destroyed. I am still unaware of when GetSite method gets called.

      #region IObjectWithSite Members
       private InternetExplorer explorer;
       /// <summary>
       /// Called, when the BHO is instantiated and when it is destroyed.
       /// </summary>
       /// <param name="site"></param>
       public void SetSite(Object site)
           if (site != null)
                explorer = (InternetExplorer)site;
       public void GetSite(ref Guid guid, out Object ppvSite)
           IntPtr punk = Marshal.GetIUnknownForObject(explorer);
           ppvSite = new object();
           IntPtr ppvSiteIntPtr =  Marshal.GetIUnknownForObject(ppvSite);
           int hr = Marshal.QueryInterface(punk, ref guid, out ppvSiteIntPtr);

III. Selecting and Displaying the toolbar at IE startup

The following method calls explorer's ShowBrowserBar method and passes the guid of your toolbar to it.

      #region Helper Methods
      private void ShowBrowserBar(bool bShow)
         //GUID_OF_YOUR_BANDOBJECT: 51B38FD0-2699-4a48-8E06-46B002F58F4A
         object pvaClsid = (object)(new Guid("51B38FD0-2699-4a48-8E06-46B002F58F4A").ToString("B"));
         object pvarShow = (object)bShow;
         object pvarSize = null;       
         if (bShow) /* hide Browser bar before showing to prevent erroneous behavior of IE*/
            object pvarShowFalse = (object)false;
            explorer.ShowBrowserBar(ref pvaClsid, ref pvarShowFalse, ref pvarSize);
         explorer.ShowBrowserBar(ref pvaClsid, ref pvarShow, ref pvarSize);

IV. Auto-Registering the BHO




       #region Com Register/UnRegister Methods
        private const string BHOKeyName = 
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects";

       /// <summary>
       /// Called, when IE browser starts.
       /// </summary>
       /// <param name="t"></param>
       public static void RegisterBHO(Type t)
           RegistryKey key = Registry.LocalMachine.OpenSubKey(BHOKeyName, true);
           if (key == null)
               key = Registry.LocalMachine.CreateSubKey(BHOKeyName);
           string guidString = t.GUID.ToString("B");
           RegistryKey bhoKey = key.OpenSubKey(guidString, true);

           if (bhoKey == null)
               bhoKey = key.CreateSubKey(guidString);
           // NoExplorer:dword = 1 prevents the BHO to be loaded by Explorer
           string _name = "NoExplorer";
           object _value = (object)1;
           bhoKey.SetValue(_name, _value);

       public static void UnregisterBHO(Type t)
           RegistryKey key = Registry.LocalMachine.OpenSubKey(BHOKeyName, true);
           string guidString = t.GUID.ToString("B");
           if (key != null)
               key.DeleteSubKey(guidString, false);

#2. Debugging toolbar

Debugging a bandobject is straight forward. Go to Project properties --> Debug and choose "Start External Program" option. Browse for internet explorer path which is C:\Program Files\Internet Explorer\iexplore.exe in my case.

But to debug the BHO code, there is a trick. Since it's managed code and obviously IE is not managed code, it's rather difficult to jump in right at the first instantiation of the first BHO.
Set your IE home page set to about:blank . That way you can start up the browser as fast as possible and go where you need to. So, start up the first IE window. Then, from VS.NET use the Attach to Process item in the Debug menu to attach to iexplore.exe. Set breakpoints in your BHO. To break within the constructor, just open a second IE window.

Some of the tools that have been very useful while debugging IE extensions:
1. fuslogvw (Visual Studio tool): Assembly Binding Viewer

#3. Installing a BandObject/BHO using an MSI:

The real challenge is not building a BandObject/BHO, but getting it to install/uninstall reliably through an MSI. To run correctly, a BHO requires registration via COM interop, but setting the vsdrpCOM property in the MSI isn't enough (this results in a successful registration most of the time, but the add-in won't remove itself at uninstall).

In my opinion it would be safe to set the MSI property to vsdrpNoDotRegister and instead create your own registration component. So to register the assembly(BHO is part of the toolbar dll in my case, which is MyToolbar.dll), use the following code within your registration code:

System.Runtime.InteropServices.RegistrationServices regservices = new

And, to unregister the assembly, you use the UnregisterAssembly method:

System.Runtime.InteropServices.RegistrationServices r = new 

i have written a installer class that is part of MyToolbar.dll and used this dll as a custom action (for both install and uninstall) in the MSI. Below is the entire installer class.

using System;
using System.ComponentModel;
using System.Configuration.Install;
using System.Runtime.InteropServices;

namespace MyToolbar
    public partial class MyToolbarInstaller : Installer
        public MyToolbarInstaller()

        public override void Install(System.Collections.IDictionary stateSaver)
            RegistrationServices regsrv = new RegistrationServices();
            if (!regsrv.RegisterAssembly(this.GetType().Assembly,
                throw new InstallException("Failed To Register for COM");

        public override void Uninstall(System.Collections.IDictionary savedState)
        {   base.Uninstall(savedState);
            RegistrationServices regsrv = new RegistrationServices();
            if (!regsrv.UnregisterAssembly(this.GetType().Assembly))
                throw new InstallException("Failed To Unregister for COM");

User Account Control considerations for IE7/Vista

This approach works all very well for XP, but if you are installing your BHO/BandObject on Vista you'll need to set the user access control correctly. One of the problems is that custom actions in MSIs run as an non-elevated user, which means that unless you are running the MSI as elevated your custom action won't have the permissions required to register the BHO/BandObject. I haven't found a way to elevate a user manually from a piece of managed code, but you can overcome this using one of two ways:

I. Write a batch file that contains the following:

msiexec /i MyToolbarMSI.msi
...and right click on the batch file, and select "Run as Administrator"

II. Use the ORCA tool (part of the Windows SDK) to set the custom actions to run as SYSTEM.

To do this, download the SDK, install and run ORCA and open your MSI. Open the custom action from the left hand pane, select your custom action and set the type to 3090. This will cause the custom action to run as the SYSTEM account and registration will be successful.

#4. Backspace, Home and other keys are not responding

If there is a text box in your toolbar and it's not responding to the Backspace or Home key. Then add the following code to your Bandobject's TranslateAcceleratorIO()'s else block, which handles all the keys other than Tab and F6.

                  //This sends messages for the backspace, home and other keys.
                    TranslateMessage(ref msg);
                    DispatchMessage(ref msg);
                    return 0;//S_OK

Here is the complete method.

        public static extern int TranslateMessage(ref MSG lpMsg);

        [DllImport("user32", EntryPoint = "DispatchMessage")]
        static extern bool DispatchMessage(ref MSG msg);
        /// <summary>
        /// Called by explorer to process keyboard events.
        /// </summary>
        /// <param name="msg"></param>
        /// <returns>S_OK if message was processed, S_FALSE otherwise.</returns>
        public virtual Int32 TranslateAcceleratorIO(ref MSG msg)
            if (msg.message == 0x100)//WM_KEYDOWN 
                //keys used by explorer to navigate from control to control
                if (msg.wParam == (uint)Keys.Tab || msg.wParam == (uint)Keys.F6)
                    if (SelectNextControl(
                            ModifierKeys == Keys.Shift ? false : true,
                        return 0;//S_OK
                    TranslateMessage(ref msg);
                    DispatchMessage(ref msg);
                    return 0;//S_OK
            return 1;//S_FALSE

#5. GAC not allowing bandobject library to uninstall from there

I tried to uninstall BandObjectLib.dll from GAC(%systemroot%\assembly) the usual way but could not succeed even after closing all instances of browser and had to remove it manually. It always shown me a message saying 'Assembly BandObjectLib could not be uninstalled because it is required by other applications'.

You may also try to delete the file in GAC directory directly by following the steps below, if you can not uninstall the usual way.

1. Run cmd in run dialog.
2. cd
(BandObjectsLib.dll is the target dll)
3. del BandObjectsLib.dll
4. cd..
5. rd
6. cd..
7. rd BandObjectsLib

#6. Toolbar is not visible

Errors in assembly loading, security permissions, or object initialization can be the cause of not displaying toolbar and these are not recorded in the Fusion log. As with ActiveX controls, a .NET object that is not initialized typically fails silently, leaving a small, grooved box where the control should be. To see such errors, you need to active the IEHost debug log. So, if the toolbar is not visible may be there is some problem with bandobject's initialization and if so, please refer the link below to setup the logs and debug the cause.
HOW to Use the IEHost Log to Debug .NET Object Hosting in Internet Explorer

#7. Using App.config file with toolbar

Initially the toolbar dll was not able to locate it's App.config file. After spending a significant amount of time i realized that because of the fact that toolband runs in IE process's appdomain, when the toolband is initialized it searches for the iexplore.exe.config in the IE executable's directory(i. e. directory containing iexplore.exe) which actually does not exist there.

So i explicitly used the path of the config file (which is MyToolbar.dll.config in my case) file, where ever i needed it.

One of the place where i used it was to configure the logs(I am using log4net for logging). Following is the code snippet i used to get the absolute path of my config file:

            Assembly executingAssembly = Assembly.GetExecutingAssembly();
            string filePath = Path.GetDirectoryName(executingAssembly.Location);
            string asmName = Path.GetFileName(executingAssembly.Location);
            string configFileName = Path.Combine(filePath, asmName + ".config");            
            //configures logs
            XmlConfigurator.Configure(new FileInfo(configFileName));

Finally the log file was generated in the internet explorer's(which is C:\Program Files\Internet Explorer on my PC) directory.

Note: I used App.config file to configure logging only. if you want to read some cusom settings of your toolbar then you might need to load the App.config and read/write it explicitly, though i did not require to do so.

#8. Building the setup project

unfortunately, msbuild.exe does not support building .vdproj(setup project). So you need to have visual studio installed on the integration/build machine that is a major restriction in .net setup projects. One alternative i found is WIX(Windows installer XML). Following are the links that provide good details to start working with WIX.

Download Windows installer XML

WIX Tutorial

Using the WiX Toolset to Integrate Setup into Your Development Process

Because of short of time i couldn't integrate WIX to my build process, but it seems very interesting and solves the purpose of integrating setup development into your daily development process. And i am sure you will find it very useful.

#9 Can't move Toolbar

Please uncheck 'Lock the Toolbars' option in the browser window, before trying to move your toolbar. If the toolbar does not move, then the solution is to do some modifications to Pavel Zolnikov's Bandobject library.
i) Add DBIMF enum and used it in DESKBANDINFO struct (defined in ComInterop.cs)
ii) Modify GetBandInfo() in BandObject.cs

Here is the code snippet.

    public enum DBIMF : uint
        NORMAL = 0x0001,
        FIXED = 0x0002, 
        FIXEDBMP = 0x0004,
        VARIABLEHEIGHT = 0x0008,
        UNDELETEABLE = 0x0010,
        DEBOSSED = 0x0020,
        BKCOLOR = 0x0040,
        USECHEVRON = 0x0080,
        BREAK = 0x0100,
        ADDTOFRONT = 0x0200,
        TOPALIGN = 0x0400,
        NOGRIPPER = 0x0800,
        ALWAYSGRIPPER = 0x1000,
        NOMARGINS = 0x2000
    public struct DESKBANDINFO
        public DBIM         dwMask;
        public Point        ptMaxSize;
        public Point        ptIntegral;
        public Point        ptActual;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
        public String        wszTitle;
        public Int32        crBkgnd;

    public virtual void GetBandInfo(
            UInt32 dwBandID,
            UInt32 dwViewMode,
            ref DESKBANDINFO dbi )

            if ( ( dbi.dwMask & DBIM.MINSIZE ) != 0 )
                dbi.ptMinSize.X = this.MinSize.Width;
                dbi.ptMinSize.Y = this.MinSize.Height;
            if ( ( dbi.dwMask & DBIM.MAXSIZE ) != 0 )
                dbi.ptMaxSize.X = this.MaxSize.Width;
                dbi.ptMaxSize.Y = this.MaxSize.Height;
            if ( ( dbi.dwMask & DBIM.INTEGRAL ) != 0 )
                dbi.ptIntegral.X = this.IntegralSize.Width;
                dbi.ptIntegral.Y = this.IntegralSize.Height;
            if ( ( dbi.dwMask & DBIM.ACTUAL ) != 0 )
                dbi.ptActual.X = this.Size.Width;
                dbi.ptActual.Y = this.Size.Height;
            if ( ( dbi.dwMask & DBIM.TITLE ) != 0 )
                dbi.wszTitle = this.Title; 
            if ( ( dbi.dwMask & DBIM.MODEFLAGS ) != 0 )
                dbi.dwModeFlags = DBIMF.VARIABLEHEIGHT;
            dbi.dwModeFlags = DBIMF.BREAK | DBIMF.ALWAYSGRIPPER;

Detailed discussion on the issue is available at the MSDN forums:


Aug 1, 2007 - Initial Release

Aug 14, 2007 - Uploaded source



A list of licenses authors might use can be found here


About the Author

Technical Lead
India India
No Biography provided

Comments and Discussions

QuestionHow to get rid of Explorer Bar? PinmemberMuhammad Saqlain Ali Khan4-Jan-10 7:37 



| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 14 Aug 2007
Article Copyright 2007 by Sonal.India
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid