Writing a BHO installer

Candle
Conceptually, installing an Internet Explorer plugin is very simple. You just have to copy your DLL onto the user’s system, and then add some registry settings so IE will load it. In practice there’s a lot of house-keeping involved to do it nicely, so users can easily uninstall and manage the add-on for example, or to check that the machine meets the minimum requirements. I wanted to use an existing framework that would make that easy, so I did some research.

NSIS was initially very attractive, since I’d used it in the past, and found it fairly user-friendly and robust. It produced a .exe though, and I’ve noticed that .msi packages seem to be a more modern approach, so I looked into alternatives. The most promising was WIX, an open-source system from Microsoft for taking an XML description of what needed to be installed, and turning that into a .msi.

The first hurdle was getting used to WIX‘s declarative approach to installation. The wxs scripts are more like makefiles, in that they declare which files need to be installed, along with conditions and dependencies, rather than asking for a procedural list of steps, as NSIS and more traditional installers do. WIX‘s way makes it easier to repair installations and lets an uninstaller be created from the same script.

I found a great tutorial by Gábor DEÁK JAHN, and pretty quickly I was able to set up a script that copied over my single DLL to a new folder in Program Files. To create an MSI installer, you take a wxs XML script, run the candle command to compile it, and then run light to package it into a .msi.

The really hard bit proved to be working out how to write to the registry. As I discussed earlier, the old way to set up the needed registry information was through a process called self-registration, where code within the DLL would be executed, and that was expected to write to the registry programmatically. These days, that approach is strongly discouraged within an installer, and instead you’re expected to list the registry keys and values you’re altering as part of the script.

This was tough, since PeteSearch relies on ATL to parse a proprietary format called .rgs to set up the required registry keys, and there’s no easy way to translate it to the required wxs XML. I was hopeful that a tool that ships with WIX, called tallow, would capture the registry changes in the right form, but when I ran it with the -s option, it crashed with an exception. This seems to be a known bug, with no solution, so I was left to hand-translate the .rgs file.

Once I got the hang of it, this didn’t take too long. The .rgs file is organized into a hierarchy of keys, each level separated by curly brackets, and at each level multiple keys can be set. Translating meant taking each key/value pair, and turning it into a full <registry> tag in the wix script. For example, this in the .rgs file:

HKCR
{
    PeteSearch.PeteSearch.1 = s ‘PeteSearch Class’
    {
        CLSID = s ‘{00e71626-0bef-11dc-8314-0800200c9a66}’
    }

becomes the following two wix tags:

<Registry
    Id=’PeteSearchReg1′
    Root=’HKCR’
    Key=’PeteSearch.PeteSearch.1′
    Action=’write’
    Type=’string’
    Value=’PeteSearch Class’
/>
<Registry
    Id=’PeteSearchReg2′
    Root=’HKCR’
    Key=’PeteSearch.PeteSearch.1\CLSID’
    Action=’write’
    Type=’string’
    Value='{00e71626-0bef-11dc-8314-0800200c9a66}’
/>

One thing that caught me out was that most of the .rgs entries were writing to the default member of the key, rather than to a named member as I initially assumed. The only one that was different was the ThreadingModel value, which was written to a named member of InprocServer32. The only non-constant value I had to write was the InprocServer32 default, which specifies the location of the dll, which I was able to reference as [INSTALLDIR]PeteSearch.dll

Once I’d converted over the registry settings, I had a functional .msi that would install the dll. The only thing left was to make sure the minimum requirements were checked before the installation went ahead. PeteSearch doesn’t work on anything earlier than Windows 2000, and only runs on IE7,  so after some experimentation I was able to add the following two condition tags as direct children of the <product> tag in my script to enforce that:

    <Property Id="INTERNETEXPLORERVERSION">
          <RegistrySearch Id=’InternetExplorerVersion’ Root=’HKLM’
           Key=’SOFTWARE\Microsoft\Internet Explorer’
           Name=’Version’ Type=’raw’>
          </RegistrySearch>
      </Property>

      <Condition Message=’PeteSearch requires Internet Explorer 7.0 or later ([INTERNETEXPLORERVERSION] found)’>
          <![CDATA[INTERNETEXPLORERVERSION >= "7.0.00000"]]>
      </Condition>
      <Condition Message=’PeteSearch requires Windows 2000 or later’>
          <![CDATA[VersionNT >= 500]]>
      </Condition>

There’s a couple of gotchas I ran into; first the condition text has to be guarded in a CDATA block, or the angle brackets get interpreted as part of the XML. Secondly, when checking the IE version, I had to enclose the constant I was comparing against in quotes, or the comparison always failed.

Putting this all together was enough to create a fully functional installer. The wxs script is available through Sourceforge, or you can download it directly here. There’s no UI apart from a progress dialog, I hope to sort out a basic license and confirmation screen in the future, to give more user feedback, and I’ll cover that when I do.

More posts on porting Firefox add-ons to IE

First PeteSearch IE beta build released

Radioactive
I just completed the installer, and so I’m now releasing the first public build of PeteSearch for IE:
http://petesearch.com/PeteSearchInstall.msi
It requires Windows 2000 or later, and Internet Explorer 7. Please give it a try, and let me know how you get on. I’ve updated the source repository, and I’ll be adding an article on how I built the installer soon.

More posts on porting Firefox add-ons to IE

BHO example for Visual Studio 6

Cow

Vlad Simionescu was kind enough to share a version of the TinyBHO sample he adapted to compile on Visual Studio 6. There’s a couple of changes in the threading model he had to make, that I don’t understand well enough to intelligently comment on, but they seem harmless. It also pops up the URL of the document now, to demonstrate the use of BSTR’s, and some simple DOM access. Thanks for that Vlad!

Download TinyBHO_VS6.zip

More posts on porting Firefox add-ons to IE

PeteSearch IE hits Alpha!

Alpha
I’ve added the last remaining missing parts, and PeteSearch running on Internet Explorer now has exactly the same features as the Firefox version! The source code is in CVS, or you can download the source as a zip here. To complete the feature set and reach alpha, I implemented search term highlighting and the summary text popups.

I’m planning on a substantial beta testing period to nail down the bugs, but before I release it as a binary I need to write an installer. Initially I was looking at NSIS, since I used that in the past, but it seems like .msi installers are the modern way to go, so I’m learning about wix, and hope to get something sorted out in the next few days. The only sticking point at the moment is figuring out how to handle the DLL registration, since apparently the code-based self-registration that the MS BHO examples use is heavily deprecated. Instead it looks like I’ll have to try and capture what the executed code is doing using a tool like tallow, and put that into a wix script. As always, I’ll let you know how that goes, and I’ll be adding some posts on other issues I’ve hit during the conversion.

More posts on porting Firefox add-ons to IE

Browser window example

Window

PeteSearch displays previews of search results in a split-screen mode, side-by-side with the results page.To do this in Internet Explorer, I needed a child window that would show and handle interaction with a web site. At first, it looked like it would be easy using AtlAxWin, but it turned out to rely on statically linking to the ATL lib, which isn’t present on the Express edition of Visual Studio. Having got this far into the port using the free version, I didn’t want to admit defeat, so I looked around for alternatives.

It turned out to involve a lot of COM boiler-plate, but with the help of Lucian Wischik’s example code, I was able to create a simple browser window class, and implement split-screen preview in PeteSearch.

You can download a zip of my latest source code here, or it’s available from through CVS on Sourceforge. There’s a class in there called CPeteWebWindow that lets you create a child window that handles rendering and navigating an external web page. Using Lucian’s example, it was surprisingly painless to implement. The process of actually adding a window to Internet Explorer turned out to be very hard, but that’s a story for another post!

More posts on porting Firefox add-ons to IE

IE DOM Event Handlers in C++

Newspaper
Getting C++ code called when there’s document event is pretty complicated. You have to create a COM class that implements the IDispatch interface, package that into a VARIANT object, and then call the element or document interface to attach it.

I’ve put together a small sample project showing how to do it, a simple BHO that attaches a callback to the document onclick event. It contains a generic C++ helper class that implements IDispatch, and calls back to a user-defined function when the event occurs. You can reuse this class for handling any DOM events. Download it all here.

This is the same technique I’m using in the IE port of PeteSearch, and it’s working well. You do have to be careful of threading issues in your callback though, since you don’t know which thread will run it! My thanks go to Ian Hart from AppxWeb, he pointed me in the right direction with this MSDN forum post.

More posts on porting Firefox add-ons to IE

Chrome equivalent in an IE BHO?

Chrome

When you’re writing a Firefox extension, you can reference images and other files you package with your installer using the chrome:// URL protocol. This is really useful if you want to inject images into a page, since you can put the images inside your extension’s folder, and then create an image tag with the src set to something like chrome://petesearch/skin/magnifier.png.

Internet Explorer doesn’t have anything like this unfortunately. No problem, I thought, I’ll just add the images to the directory where the DLL is installed, and reference them from there. After trying that, I realized that the images were never being loaded, and though I couldn’t find any documentation to back this up, decided it was probably blocked by a security policy. Remote pages accessing files from the local disk, even if they’re just images, could theoretically be used as part of an exploit, or at least to access some information about the user’s file system. IE doesn’t know that the local file reference has been inserted by our BHO, so it blocks it.

I compared notes on this with Georges-Etienne Legendre since he was also hitting this problem. I’m developing on Vista, it appears that on XP you can still reference local image files on http pages, but not ones that use the https protocol.

Here’s the suggestions I’ve had on how to inject a local image into a remote page:

  • Use the res: protocol to reference an image within the BHO’s dll. This was suggested on the MSDN extensions forum by Rob of IECustomizer.com. I haven’t tried this yet, but I’ve got a strong feeling that this protocol will be at least as restricted as file:, if not more, so I’m not holding out much hope.
  • Write an Asynchronous Pluggable Protocol to implement something like data:. This was suggested by Georges-Etienne, apparently IE7Pro does something similar to solve this problem. It seems like it would be quite a lot of work, and I’m not sure about the details of how you could use it to solve the problem.

For now, I’ve decided to side-step the problem by hosting the images I need on my own server. This works fine, but it’s a bit wasteful of network resources, and I hoped to keep the extension from having any dependencies on a single server.

I’d love to hear any suggestions on other ways to tackle this, or more info on the security restrictions that cause the problem.

More posts on porting Firefox add-ons to IE

BHO Examples

Blueprint
One of the problems I ran into when I started looking at converting PeteSearch from a Firefox plugin to an Internet Explorer extension was finding good example code. There are a couple of great articles on MSDN that cover how to write a BHO, but neither include complete source code. Here’s the list of all the code samples I managed to find, and a couple I wrote myself:

A very simple skeleton BHO that I wrote:
http://petewarden.typepad.com/searchbrowser/2007/05/porting_firefox_1.html

A more complex example based on my Firefox add-on:
http://petewarden.typepad.com/searchbrowser/2007/06/porting-firefox.html

From Sven Groot, the source to his FindAsYouType extension:
http://www.ookii.org/software/findasyoutype/
http://www.ookii.org/download.ashx?id=FindAsYouTypeSrc

The SurfHelper pop-up blocker from Xiaolin Zhang:
http://www.codeproject.com/shell/surfhelper.asp

A simple example covering all the BHO events from René Nyffenegger:
http://www.adp-gmbh.ch/win/com/bho.html

More posts on porting Firefox add-ons to IE

Porting Firefox extensions to Internet Explorer – Key Commands

Pianokeys
After getting the basic page analysis working, I wanted to use the information I was gathering, so the next step was to get the hot-key commands working.

In Firefox I’m able to set up command key-bindings in the XUL files of my add-on, and call back into the extensions Javascript. Internet Explorer doesn’t have this pre-packaged support for adding key commands, so instead I have to catch the system key events, detect the combinations I’m interested and call the right functions manually.

There are different ways to do this, depending on what you need. Sven describes how to capture all key events in IE from a BHO, even if the focus is on the address bar. Looking at that made my head hurt, it needs some thread-local variables and mapping to remember which thread is associated with which document.

Luckily, I realized that my needs were a bit simpler. I’m happy to have my commands only work when the focus is on the document itself, which meant I could use the DOM event handlers exposed through IHTMLDocument2 to capture key events.

Attaching a C++ callback to an event handler in the MS DOM is not trivial, and involves some COM boilerplate, but I had a helper class I use to capture onclick events for elements. I’ll cover that along with the rest of my DOM helper functions in a future post.

Reusing that, getting called when a key event occurred was quite easy, though one wrinkle I hit was that onkeypress doesn’t get called for all keys, such as those produced when control is held down. I worked around this by synthesizing an equivalent using onkeydown/up, since they do get called for all keys.

One odd thing about these handlers in IE is that they don’t get passed the event information directly as a parameter. Instead you have to ask the current window what the last event was, and pull the information from that. To get the current window, you have to ask the document, and to get the document, I had to query the browser, since that’s all I store in my class, so the code is a bit verbose. It does the job thought, even if it is uglier than I’d like.

The next hurdle was working out the key codes for the events I was interested in. Here’s what I found for the unusual keys I needed:

  • Left Arrow = 37
  • Up Arrow = 38
  • Right Arrow = 39
  • Down Arrow = 40
  • Control+Equals= 187
  • Control+Forward Slash = 191

I then added a giant switch statement to handle all the key combinations I was interested in, and call the right functions. Once that was wired up, I also implemented saving the enabled state of the add-on in the registry, so users can turn it off when they’re not using it, and it will still be off when they restart IE.

More posts on porting Firefox add-ons to IE

XMLHttpRequest in C++ using IXMLHTTPRequest

Lightbulb_3

Sven Groot, whose IE BHO development tips I mentioned earlier, has another great post on using the IXMLHTTPRequest object asynchronously in C++. He explains exactly how to use that object’s callback from C++, with a code example. This was the problem that forced me to write my own implementation, since the official documentation had no explanation of how to do this. The other examples I could find had the bits I was interested in mixed with a lot of other functionality, and I didn’t have the knowledge to disentangle them.

I’d highly recommend taking a serious look at Sven’s example if you’re looking for a way to do XMLHttpRequest’s in C++, it really helped me understand what was going on!

More posts on porting Firefox add-ons to IE