Developing a Browser Toolbar: Installation System (4/5)

This post series reflects my article “Developing a Browser Toolbar” published in the ASPects in January 2010 (Volume 23, Issue 1), a magazine of the Association of Shareware Professionals (ASP).

Now we have a toolbar for Internet Explorer and Firefox, but how do we get them installed? There is only one installation tool I’m using also for all my other products that can do almost everything: Inno Setup. Here is what you need for the installation of both toolbar versions.

Mozilla Firefox Toolbar Installation

Again it is much easier to install a new toolbar for the Firefox browser. You only need to copy your XPI file to the Firefox extension directory. The toolbar will then be installed at the next browser start. So we need only one additional Pascal function in our Inno Setup code to figure out the extension directory of Firefox:

function GetFirefoxExtensionsPath(Param: String): String;
var
    FirefoxVersion, FirefoxInstallPath: string;
begin
    if (RegQueryStringValue(HKLM, 'SOFTWARE\Mozilla\Mozilla Firefox',
            'CurrentVersion', FirefoxVersion)) then begin
        if (RegQueryStringValue(HKLM, 'SOFTWARE\Mozilla\Mozilla Firefox\' + FirefoxVersion +
                '\Main', 'Install Directory', FirefoxInstallPath)) then begin
            if (not DirExists(FirefoxInstallPath +
                   '\extensions\toolbarebay@ab-tools.com')) then begin
                Result := FirefoxInstallPath + '\extensions';
            end;
        end;
    end;
end;

Microsoft Internet Explorer Toolbar Installation

To install the toolbar for the Internet Explorer we first have to register the strongly-named assembly in the Global Assembly Cache (GAC) by using the gacinstall flag of the file section provided in the current Inno Setup version. Additionally we need to make quite a few registry changes. You can copy the following code into the registry section of your Inno Setup script and replace all variables by your own values (I’ve shortened the Inno Setup syntax a little bit to get it more compact):

HKCR: CLSID\{{%GUID%}; Flags: uninsdeletekey
HKCR: CLSID\{{%GUID%}; ValueType: string; ValueName: ; ValueData: %LONG_NAME%
HKCR: CLSID\{{%GUID%}; ValueType: string; ValueName: MenuText; ValueData: %LONG_NAME%
HKCR: CLSID\{{%GUID%}; ValueType: string; ValueName: HelpText; ValueData: %DESCRIPTION%
HKCR: CLSID\{{%GUID%}\Implemented Categories\{{00021494-0000-0000-C000-000000000046}
HKCR: CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: ; ValueData: mscoree.dll
HKCR: CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: ThreadingModel; ValueData: Both
HKCR: CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: Class; ValueData: %CLASS%
HKCR: CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: Assembly; ValueData: %NAMESPACE%, Version=%VERSION%, Culture=neutral, PublicKeyToken=%PUBLIC_KEY%
HKCR: CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: RuntimeVersion; ValueData: v2.0.50727
HKLM: Software\Classes\CLSID\{{%GUID%}; Flags: uninsdeletekey
HKLM: Software\Classes\CLSID\{{%GUID%}; ValueType: string; ValueName: ; ValueData: %LONG_NAME%
HKLM: Software\Classes\CLSID\{{%GUID%}; ValueType: string; ValueName: MenuText; ValueData: %LONG_NAME%
HKLM: Software\Classes\CLSID\{{%GUID%}; ValueType: string; ValueName: HelpText; ValueData: %DESCRIPTION%
HKLM: Software\Classes\CLSID\{{%GUID%}\Implemented Categories\{{00021494-0000-0000-C000-000000000046}
HKLM: Software\Classes\CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: ; ValueData: mscoree.dll
HKLM: Software\Classes\CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: ThreadingModel; ValueData: Both
HKLM: Software\Classes\CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: Class; ValueData: %CLASS%
HKLM: Software\Classes\CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: Assembly; ValueData: %NAMESPACE%, Version=%VERSION%, Culture=neutral, PublicKeyToken=%PUBLIC_KEY%
HKLM: Software\Classes\CLSID\{{%GUID%}\InprocServer32; ValueType: string; ValueName: RuntimeVersion; ValueData: v2.0.50727
HKLM: SOFTWARE\Microsoft\Internet Explorer\Toolbar; ValueType: string; ValueName: {{%GUID%}; ValueData: %LONG_NAME%
HKLM: SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{{%GUID%}; Flags: uninsdeletekey
HKLM: SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{{%GUID%}; ValueType: dword; ValueName: NoExplorer; ValueData: 1

To not write useless trash to the user’s computer, the registry changes should only be performed and the files only be copied if the .NET Framework 2.0 (or higher) is installed on the system, because this is needed for the Internet Explorer toolbar as already written above. You can check the availability of the .NET Framework 2.0 quite easy with following Pascal function:

function CheckForDotNet(): Boolean;
begin
    Result := RegKeyExists(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727');
end;

These are the steps to create an Inno Setup installer for both toolbar versions. Of course, you can combine them in a single setup file that installs in Internet Explorer as well as the Firefox version depending on which browser is installed on the system.

The last post will be a short summary.

Contents of Post Series “Developing a Browser Toolbar”:

Developing a Browser Toolbar: Microsoft Internet Explorer (3/5)

This post series reflects my article “Developing a Browser Toolbar” published in the ASPects in January 2010 (Volume 23, Issue 1), a magazine of the Association of Shareware Professionals (ASP).

The first decision to make is which programming language you want to use for developing the Internet Explorer toolbar. I did some research in the web and found examples for C++, Visual Basic 6 and .NET. There seem to be some visual styles issues; it obviously does not look so good on Windows Vista and Windows 7 systems by using the C++ version. And as I really don’t like to develop in Visual Basic 6 anymore, I decided to go the .NET way. The only disadvantage of this decision is that the user needs to have the .NET Framework 2.0 (or higher) installed on the system. But I can live with that, because it is very common already.

Since almost all of my products are developed in .NET, I already had the Visual Studio 2008 installed on my computer. If not, you’ll need at least the Express Edition (version 2005 should be enough, too) for the next steps. I decided to develop the toolbar in C#, but Visual Basic .NET could do the same thing, of course.

As a good starting point I found this and this article at the Code Project webpage. If you want to read more about the COM component, you can also read the C++ tutorial, but that’s not necessarily needed. By using the demo source code of those articles you should get a working toolbar – at least on a Windows XP system. But there were some issues I came across that needed to be fixed and therefore I will describe them in more detail here:

Making Toolbar Show up Correctly on All Operating Systems

By using the demo code of the articles mentioned above, I got the toolbar to work quite fast on my Windows XP testing machine. I was naively thinking that if the toolbar works on Windows XP with Internet Explorer 8, it will also work on Windows Vista and Windows 7 with the same Internet Explorer version. But indeed, I had to learn that this is absolutely not the case! It either just does not show up at all or so far on the right side, that you can only see the toolbar if you have a horizontal resolution of at least 2,000 pixels. So I had to search for a solution, but most changes to the code resulted in the toolbar working either on the one or on the other operating system or browser version combination. After some hours of frustrated testing, I changed the GetBandInfo procedure of the BandObjectsLib class in the following way. Although I’m still not absolutely sure why, it works fine now on all operating system:

public virtual void GetBandInfo(UInt32 dwBandID, UInt32 dwViewMode, ref DESKBANDINFO dbi)
{
    if ((dbi.dwMask & DBIM.MINSIZE) != 0)
    {
        dbi.ptMinSize.X = this.MinimumSize.Width;
        dbi.ptMinSize.Y = this.MinimumSize.Height;
    }

    if ((dbi.dwMask & DBIM.MAXSIZE) != 0)
    {
        dbi.ptMaxSize.X = this.MaximumSize.Width;
        dbi.ptMaxSize.Y = this.MaximumSize.Height;
    }

    if ((dbi.dwMask & DBIM.ACTUAL) != 0)
    {
        dbi.ptActual.X = this.Size.Width;
        dbi.ptActual.Y = this.Size.Height;
    }

    if ((dbi.dwMask & DBIM.BKCOLOR) != 0)
    {
        dbi.dwMask &= ~DBIM.BKCOLOR;
    }

    dbi.dwModeFlags = DBIMF.BREAK;
}

Nicer Appearance on Windows XP and above

If you don’t add the following event handler to the BandObjectsLib class, your toolbar will still work, but will just not look very good on Windows XP and above. The if-statement in the event function additionally makes sure that the toolbar still works on older operating systems like Windows 98, 2000 and ME. Otherwise it would throw an exception on these operating systems. Here is the code I’ve used to get it to work correctly on all operating systems:

[DllImport("uxtheme", ExactSpelling = true)]
public extern static Int32 DrawThemeParentBackground(IntPtr hWnd, IntPtr hdc,
                                                     ref Rectangle pRect);

protected override void OnPaintBackground(PaintEventArgs e)
{
    if (System.Environment.OSVersion.Platform >= PlatformID.Win32NT &&
           (Environment.OSVersion.Version.Major == 5 &&
            Environment.OSVersion.Version.Minor >= 1 ||
            Environment.OSVersion.Version.Major >= 6) &&
           this.BackColor == Color.Transparent)
    {
        // Only if operating system is Windows XP or higher
        IntPtr hdc = e.Graphics.GetHdc();
        Rectangle rec = new Rectangle(e.ClipRectangle.Left,
            e.ClipRectangle.Top, e.ClipRectangle.Width, e.ClipRectangle.Height);
        DrawThemeParentBackground(this.Handle, hdc, ref rec);
        e.Graphics.ReleaseHdc(hdc);
    }
    else
    {
        base.OnPaintBackground(e);
    }
}

No Serialization Allowed

When developing a Firefox toolbar you can use the Mozilla preferences service to store and load user-defined values inside Firefox itself. Because there is no equivalent in Internet Explorer and I’m using XML serialization in many of my other .NET products, I wanted to use it in the toolbar project, too. This worked fine at first sight, but if the Protected Mode is enabled in Internet Explorer 8 (and it is by default, at least since Windows Vista), it shows an ugly warning dialog to the user whenever the toolbar is initialized. I won’t explain the reason in detail here, but just don’t use serialization in Internet Explorer toolbars. You can save user-defined values either without serialization in the file system below the local application data directory or simply by using the registry.

Automatic Online Update

As I did in the Firefox version, I also wanted the Internet Explorer toolbar to come with an automatic update feature. Because there is no update system for toolbars in Firefox, you have to implement it yourself. But this is quite easy, because you can use, as in any other .NET application, the WebClient class for doing a HTTP request to first ask if there is a new update available and then to receive the update file if needed. On the server side I have a small PHP script handling the update requests. The update file which is downloaded is the normal setup executable that just overrides all files with the new ones. The only thing you have to care about is the way you call the executable setup file after downloading, because otherwise a User Account Control (UAC) prompt will be shown. I’ve written this procedure that you can use for executing a file from within the toolbar code without any warning displayed to the user:

private void startProcess(string fileName, string arguments)
{
    System.Diagnostics.ProcessStartInfo startInfo =
        new System.Diagnostics.ProcessStartInfo();
    startInfo.UseShellExecute = true;
    startInfo.WorkingDirectory = Environment.CurrentDirectory;
    startInfo.FileName = fileName;
    if (Environment.OSVersion.Platform >= PlatformID.Win32NT &&
            Environment.OSVersion.Version.Major >= 6)
        // Only if operating system is Windows Vista or higher
        startInfo.Verb = "runas";
    else
        startInfo.Verb = "open";
    startInfo.Arguments = arguments;
    startInfo.ErrorDialog = true;
    try
    {
        System.Diagnostics.Process process = System.Diagnostics.Process.Start(startInfo);
        process.WaitForExit();

        MessageBox.Show(objToolbarData["msg.restartBrowserText"],
                        objToolbarData["msg.restartBrowserTitle"],
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch (Exception ex)
    {
        if (debugMode) MessageBox.Show(ex.ToString());
    }
}

Uninstall Button Inside the Toolbar

That’s the only thing which is easier to implement in Internet Explorer than in Firefox; it is enough to call the uninstall executable (again with the startProcess procedure above) of the installation system (see next post###) to uninstall the toolbar again. It will disappear then after browser has been restarted (just as on Firefox).

It’s done; the Internet Explorer version of our toolbar is ready, too! It will work on Internet Explorer 6 or higher running on Windows 98 or higher with an installed .NET Framework 2.0.

In the next post I’ll explain how we get the toolbars installed.

Contents of Post Series “Developing a Browser Toolbar”:

Developing a Browser Toolbar: Mozilla Firefox (2/5)

This post series reflects my article “Developing a Browser Toolbar” published in the ASPects in January 2010 (Volume 23, Issue 1), a magazine of the Association of Shareware Professionals (ASP).

Developing a toolbar for Firefox is quite easy: it’s all done by using XML, a little bit of CSS and especially JavaScript. The last one is also the only crux of the matter, because I really don’t like to develop in JavaScript. But anyway, it’s straightforward in this case.

I found a very good resource in the web. This tutorial explains the development of a Firefox toolbar in detail and saved me a lot of research work. After you went through the online tutorial, you should already have a fully-functional Firefox toolbar. There are only two things left:

Automatic online update

I wanted my toolbar to receive automatic updates from my webserver. But this is also quite easy by using the integrated update system of Firefox. On the same website there is a good tutorial for adding automatic update support, too.

Uninstall button inside the toolbar

The disreputability of toolbars is surely not least based on the fact that most of them are really hard to uninstall. Although Firefox provides uninstall support to the user already by using the add-ons manager, I wanted an uninstall button to be included directly into the toolbar itself. After doing some research in the web and at the Mozilla Developer Center, I got together the following piece of code that first successfully uninstalls the toolbar, second shows a webpage to the user (something like “We’re sad that you uninstalled…”) and finally tells the user that a browser restart is needed to finish the uninstallation:

try {
    var tb = document.getElementById('ABTools-Toolbar');
    var text = ABTools_ToolbarData["msg.uninstallToolbarText"].replace("%name%",
                                   ABTools_ToolbarData["toolbar.name"]);
    if (!window.confirm(text))
        return;

    var gExtensionManager = Components.classes["@mozilla.org/extensions/manager;1"]
                            .getService(Components.interfaces.nsIExtensionManager);
    var rds = gExtensionManager.datasource;
    if (gExtensionManager.uninstallItem) gExtensionManager.uninstallItem(ABTools_id);
    if (gExtensionManager.uninstallExtension)
        gExtensionManager.uninstallExtension(ABTools_id);

    ABTools_guid = "";
    ABTools_saveSettings();

    ABTools_LoadURL(getABToolsHomepageLink(9));

    alert(ABTools_ToolbarData["msg.restartBrowserText"]);
} catch(e) {
    if (ABTools_DebugMode) alert(e);
}

After going through these steps your Firefox toolbar is ready to get installed! It will work on Firefox Version 1.5 or higher, not depending on the version of the operating system.

In the next post I will go to the more complicated browser.

Contents of Post Series “Developing a Browser Toolbar”:

Developing a Browser Toolbar: Introduction (1/5)

This post series reflects my article “Developing a Browser Toolbar” published in the ASPects in January 2010 (Volume 23, Issue 1), a magazine of the Association of Shareware Professionals (ASP).

Beside commercial products I’m directly selling to customers, over the past few years I’ve also created many freeware products. This is not the right place for discussing the pros and cons of toolbars, but I decided that integrating a toolbar into the installers of my products would be a good way to earn some money with my freeware products.

Therefore I’ve worked together with a German advertisement company that provided me with a ready-to-use toolbar. Because there arose some significant problems with their toolbar some time ago, I decided to develop a toolbar on my own.

I will not be able to describe the steps for developing such a browser toolbar in detail or we’ll run out of pages here. If you also need to create a toolbar on your own in the future, I can give you some hints and links to good resources that makes this challenge far easier, and if you need help, ask in the ASP’s .technical newsgroup (or just add a comment below).

First of all, I had to define on which browser the toolbar should work. Of course, two browsers come into consideration immediately: Internet Explorer and Firefox. I’ve also taken a look at Opera and Chrome, but both browsers did not provide real add-on support and therefore I decided to concentrate on Internet Explorer and Firefox for the moment – the most prevalent browsers.

As I read up on this matter I found that Internet Explorer gives the developer a hard time also on this topic. Therefore let’s start with the easier one in the next post.

Contents of Post Series “Developing a Browser Toolbar”: