Introduction

A lot has been already said about extending Windows and Internet Explorer with
Band Objects, Browser Bands, Toolbar Bands and Communication Bands. So if you
are familiar with COM and ATL you even might have implemented one yourself.
Well, in case your were waiting for an easy way to impress your friends with
something like Google Toolbar here it is - the .NET way (or should I say
Windows Forms and COM Interop way?). In this tutorial I am going to show how to
create any of the mentioned above Band Object types with the help of the BandObject
control. Later I will also talk about some implementation details of the BandObject.

Hello World Bar step by step

1.

Build a Release version of BandObjectLib and register it in the Global Assembly
Cache. The easiest way to do this is to open BandObjectLib.sln in Visual
Studio, set the active configuration to Release and select 'Rebuild Solution' from
the 'Build' menu. The second project in the solution - RegisterLib - is a C++
utility project that performs the 'gacutil /if BandObjectLib.dll' command that puts
assembly into GAC.

As you probably already know, Band Objects are COM components. And for the .NET
framework to find an assembly that implements a COM component it must be either be
registered in the GAC or located in the directory of the client application. There
are two possible client applications for Band Objects - explorer.exe and
iexplorer.exe. Explorer is located in the windows directory and IE somewhere
inside 'Program Files'. So GAC is actually the only one option in this case.
Thus .NET assemblies that implement Band Objects should be registered in GAC
and all libraries they depend on - like BandObjectLib.dll - should also be
there.

Assemblies in the GAC must have strong names and thus key pairs are required. I have
provided the BandObjects.snk file with a key pair but I encourage you to replace it
with your own. See the sn.exe tool for more details.

2.

Create a new Windows Control Library project and call it SampleBars. We are
going to rely on the base functionality of BandObjectLib so we have to add a
reference to BandObjectLib\Relase\bin\BandObjectLib.dll. As we are developing a
'Hello World Bar', rename UserControl1.cs and the UserControl1 class
inside it appropriately - into HelloWolrdBar.cs and HelloWorldBar.
Also put the following lines at the beginning of HelloWorldBar.cs:

using BandObjectLib;
using System.Runtime.InteropServices;

3.

Make HelloWorldBar class inherit BandObject instead of System.Windows.Forms.UserControl.
As I mentioned earlier, Band Objects are COM components so we should use the Guid
attribute. Use guidgen.exe to generate your unique GUID or you can use the one I
have generated for you:

[Guid("AE07101B-46D4-4a98-AF68-0333EA26E113")]

We also have to sign our assembly with a strong name. You can do this by putting
the following line into AssemblyInfo.cs file:

[assembly: AssemblyKeyFile(@"..\..\..\BandObjects.snk")]

4.

Now its time to decide what kind of Band Object we want to develop. Lets make
it an Explorer Toolbar as well as a Horizontal Explorer Bar (also known as a
Browser Communication Band). All we need to do to implement this decision is to
add custom BandObject attribute to our HelloWorldBar class:

That's enough to make our control available through 'View->Explorer Bars' and
'View->Toolbars' explorer menus. It also takes care of menu item text -
"Hello World Bar", and hen the menu item is highlighted status bar displays "Shows
bar that says hello.". Don't you like declarative programming and custom
attributes?

5.

Now it is time to open HelloWorldBar.cs in the Visual Studio Designer and put some
controls on it. Although in my version of HelloWorldBar I decided
to put a single button with 'Say Hello' caption on it you are free to do
something more personalized. I made the size of the button equal to the size of
the control's client area and also set its Anchor property to the
combination of all possible styles - 'Top, Bottom, Left, Right'. The background
color is 'HotTrack' and ForeColor is 'Info'.

The BandObject control has several properties specific to the Band
Objects (and so classes derived from it) - Title , MinSize,
MaxSize and IntegralSize. I set Title for
HelloWorldBar to "Hello Bar" and both MinSize and Size
to '150, 24'. Oh, and in button's On Click event handler I put code that
displays a message box. This is what my final code looks like (and most of it was
generated by VS.Net):

6.

Ok, now we are ready to build SampleBars.dll but its not enough to see it in
explorer yet. We have to put our assembly into the GAC as well as register it as a
COM server. There are tools - gacutil.exe and regasm.exe that do just this. The C++
utility project named Register in my version of the SampleBars solution liberates
me from using these tools manually. It has no files in it, just the following
post-build command (debug version):

Of cause you have to make sure that Register project is the last one to be built in the
solution using Project Dependencies / Build Order.

After building the solution, and executing the gacutil and regasm commands, we are finally ready to
start Explorer and see our toolbar and explorer bar. And if you did everything
right you should be able to see something like the picture at the top of the
article. On this picture you can also see how HelloWorldBar looks
in the Windows Taskbar. To achieve this all you need to do is to modify BandObject
attribute adding the BandObjectStyle.TaskbarToolBar flag.

Note

There are several issues that you might face developing a band object. First of
all, every time you rebuild your project Visual Studio tends to generate new
version of the assembly. It does this because of the following line in
AssemblyInfo.cs:

[assembly: AssemblyVersion("1.0.*")]

I recommend using something like "1.0.0.0" or you'll end up with multiple
versions of your assembly in GAC. As a matter of fact, according to Jeffrey
Richter, the auto increment feature of assembly version is a bug; the original intent
was to increment the version of a file, not the assembly.

Another issue, more specific to BandObjects, is that explorer caches COM
components. This means that even after you deployed a new version of your
assembly into GAC, Explorer will not use it until restarted. What may help is
setting the 'Launch folder windows in separate process' Explorer setting on. Also
if you are getting "Unexpected error creating debug information file..." it is
also due to the fact that previous version of your assembly is loaded into
Explorer's process space.

Inside the BandObject

Ok, now we can look inside the BandObject class implementation. Lets
start with ComComInterop.cs file. Explorer requires band objects to implement a
set of COM interfaces - IObjectWithSite, IDeskBand and
others. Unfortunately these interfaces are not available in the required form of type
library so you cannot start using them just by adding a new reference to
your project. These interfaces declarations are available in the form of C++
classes and MIDL interfaces. So before using them in .NET you have to convert
these declarations into one of the .Net languages. This file also contains
several structs and enums used by these interfaces. The whole process of
converting is quite straightforward - you see HWND make it IntPtr,
IUnknown - Object etc. Probably the most difficult
for me was dealing with the DESKBANDINFO structure. You see, in the C++
version one of its parameters is declared as

WCHAR wszTitle[256];

It took quite a lot of debugging until I figured out what the C# version should look
like. Note the use of CharSet.Unicode and that SizeConst
is set to 255 not to 256.

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]publicstruct DESKBANDINFO
{
publicUInt32 dwMask;
public Point ptMinSize;
public Point ptMaxSize;
public Point ptIntegral;
public Point ptActual;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
publicString wszTitle;
public DBIM dwModeFlags;
publicInt32 crBkgnd;
};

And so the BandObject class implements required interfaces. The entry
point is the IDeskBand.GetBandInfo method. Its implementation simply
gets the values of the Size, MinSize, IntegralSize
and Title properties, and populates the DESKBANDINFO structure.
That gives Explorer hints how to display and resize band object.

The implementation of other methods of IDeskBand interface was easy: ShowDW()
delegates to Control.Show() or Hide(), CloseDW()
calls Dispose() and GetWindow() simply returns the Handle
property of the control.

IObjectWithSite is equired to establish communication with the hosting
Explorer process. Inside the SetSite() method of the BandObject control
tries to get a reference to an IWebBrowser interface - an interface
implemented by the top-level object of Explorer. It will be available through the
BandObject.Explorer property. In the case of a taskbar toolbar there
is no IWebBrowser interface so it handles this situation
gracefully. As soon as a pointer to IWebBrowser is retrived, BandObject
fires the ExplorerAttached event. Handling this event is useful when
you want to add extra initialization code - subscribing to Web Browser events
etc.

The IInputObject implementation is more interesting. This interface is
required if you want your band object to participate in processing of keyboard
input. The user can navigate from one explorer interface object (address bar, folder
view) to another by pressing 'Tab' or 'Shift+Tab'. When it is your band
object's turn to be activated or deactivated, Explorer calls the UIActivateIO()
method. BandObject's implementation of it simply calls Select()
on one of its child controls that acquires focus. Which control to select
depends on the tab order of controls and whether user navigates forward or
backward (with Shift key). BandObject also makes sure that focus
can leave it (in case last control is selected and user presses Tab). This
logic is implemented inside the TranslateAcceleratorIO() method. It
first checks if the 'Tab' or 'F6' keys were pressed. Then depending on the state of
'Shift' key it tries to move focus from one child control to another using the SelectNextControl()
method. The last parameter of SelectNextControl is false
as we don't want to cycle through controls forever (from last to first and vice
versa). If there is no next control we return zero which signals to Explorer
that we don't know how to process this command. So Explorer itself processes
the command, moving focus to an appropriate user interface object.

And finally my favorite part: the Register() and Unregister()
methods. These methods are adorned with Com{Un}registerFunction attributes
so the regasm.exe tool knows to call them when assembly is registered as a COM
server. Register function checks its input parameter for presence
of BandObjectAttribute. If it is present then its Name,
Style and HelpText properties are used to create
apropriate registry settings. For instance, to make your COM component to be
considered as a 'Browser Communication Band' you have to mark it as
implementing the 'Browser Communication Band' COM category. To make it an Explorer
toolbar you have to register its CLSID under SOFTWARE\Microsoft\Internet
Explorer\Toolbar. But you don't have to worry about these details.
All you need to know is what BandObjectStyle flag to use and Register()
takes care of the rest. Similarly, the Unregister() method takes care of
what have to be removed from the registry when assembly is unregistered.

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.

I'm writing a custom .NET DeskBand for windows 7, and every time I try to
load it, I get the following message: "The (...) toolbar isn't compatible
with this version of windows".
I have read that implementing IDeskBand2 was indeed all that was necessary for this. How I can do this?

If you don't mind me asking, where did you read that implementing IDeskband2 would make this go away?

I just tried implementing IDeskband2 within my existing toolbar (I haven't tried very hard), defaulting my variable to indicate support for translucency. Now Explorer in Windows 7 simply crashes immediately as soon as I try to display it on the taskbar.

I haven't researched this well, but I notice the Microsoft documentation for IDeskband2 is advising that it's deprecated and suggests people use thumbnail toolbars instead. Some quick searching revealed a few links about thumbnail toolbars. eg. Here.

Is it possible that Windows 7 pops up the message because it doesn't want to support deskbands at all, and that Microsoft is trying to shunt everyone towards using thumbnail toolbars instead? The nature of the taskbar interface and how it works has changed quite a lot with Windows 7 such that toolbars no longer fit too well, so I wouldn't find it too surprising.

I am trying to implement a search(simple) which has similar input boxes as the windows explorer has. When I click the search(button) in the left of my band object I want the files to be shown in right pane(same as windows search does). Kindly let me know how to do that?
Thanks
Saket

I created one of those toolbars and now I wanted to modify it a bit. But when I build it and deploy it using that gactil and regasm commands I only see that old versioned toolbar with the button and the messagebox. Why are there no changes?

I have created my toolbar using combinations of various articles on codeproject but mainly based on Pavel Zolnikov's BandObjectLib. My toolbar has only BandObjectStyle.ExplorerToolbar flag. The toolbar shows and hides correctly using the View->Toolbar menu however I have a BHO object employed only to call ShowBrowerBar within the SetSite method and this simply will not work on IE8, IE7 works fine, does anyone have a solution for this as I've been tearing my heair out trying to find one.

Ok guys i pass big time reading all this messages and just finding clues on how to make a working setup project, main problem always was registering the assembly as COM server.

All .NET 3.5 VS2008 SP 1s

The first warn is: while you can in Setup Project -> Global assembly Cache Folder -> Primary output for (your deskbar) -> Properties
Set the Register property to vsdrpCOM this never works for me, dont know why i just let it at value vsdrpDoNotRegister.

Assuming you have your deskbar project as class library that includes BandObject library and the Interop.SHDocVw library, and you sign this assembly, in VS2008 is a ckeck in project properties, very easy and:
Select the Project, Right Click, Properties, in Applicattion Tab, click on "Assembly Information" button and check "Make assembly COM-Visible" for your Deskbar project!

Now you have a other/new solution for your setup project, you add to this project the primary output of your Deskbar project, add to special folder of GAC the 3 assemblys (the primary output, the BandObject.dll and Interop.SHDocVw)

Now comes that was the trick part for me: In this solution (setup project) make a new project of type class library lets call it Deskbar.COMInstaller, now copy the Install.cs class of commandbar example the only change you need is to replace the string of the fullname of the assembly it comes with:
"CommandBar, Version=1.1.0.0, Culture=neutral, PublicKeyToken=f62fe54d9a592d72, Custom=null"

I have read you article and decide to create my own control which will be displayed in the taskbar...

I have download your examples and was trying to compile them. After I have registered com object I have seen that new menu item was displayed in the Toolbars menu. Than I have tried to check it to display just compiled control... BUT nothing happened after.. no control was added...

Could you please help me to determine where is mistake.. Thanks in advance!

You should not rate articles based on your intelligence, or on whether the proposed solution works for you. Instead, vote on the article, then if you have problems, comment. Otherwise, this community will do better with people who understand how to rate articles, or at least have tried to write an article.

Setting the web reference seems to work fine and all is well right up to the point where I try to instantiate the service proxy object. I receive an error message saying "Could not find default endpoint element that references contract 'URLServiceReference.URLServiceSoap' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element." I'm assuming this means my app config is not being loaded when the extension is loaded. How do I solve this?

Never mind. I just instantiated the binding and address objects myself and configured the service client on the fly. That will work ok for my prototype. Next I have to figure out how to control the browser.

I converted the project to visual studio.net 2008, after a couple of issues I was able to compile the project and Visual Studio.NET 2008 did a good job in putting the dlls in GAC and everything. The option to select the toolbar did show up in Menubar> view> Toolbars, but I could NOT check the option and so the toolbar didn't show up. Anybody know how to fix this?

I have the same problem as Ranjan. I'm using VS2008 and IE8. After I compiled and registered the add-on I had the coise in View->Toolbars but it wouldn't be displayed?! If i enable the Add-on a msgbox ask me if I'm shure to enable it and I clicked 'yes' but nothing happend. If i click the add-on again it also ask me to disable it. There for I think the add-on will be starded but it will not apper. I also tried another add-on written by a frind and the only thing I could see was a panel with a close-button [x] on it? And now I'm wondering cause he did not do anything different than me oO. Can someone out there help me please.