“SpicIE is a framework which allows you easily to extend Internet Explorer 7/8 with your own plugins. SpicIE wraps/hides the IE COM extension interfaces and makes it easy to develop browser extensions in managed programming languages.”
In my opinion, this is something long overdue. Though I really haven’t had a need to write a browser plugin for anything, my perception – based on the availability of plugins and anecdotal evidence – is that it’s far easier to do in, say, Firefox or most other browsers than it is in Internet Explorer. That being the case, when I saw spicIE today, I decided to download it and see just how much would be involved in writing my first plugin for IE.
First, I downloaded spicIE and installed it. The install gives you a spicIE program group with two sample solutions, a help file and installation/deinstallation instructions:
It also installs a Visual Studio template for spicIE projects:
The template creates a project for you, including install/deinstall batch files, a strong-naming key and a Plugin.cs file:
Plugin.cs is the starting point for your plugin and inherits from SpicIE.Host. The template apparently didn’t like my project name of LoveTheDot.PlugIn.IE and this resulted in some initial build errors:
This is listed in the known issues, which I didn’t read before starting:
“In case you're creating a new project from the SpicIE template, either in C# or VB.NET, you should be aware of a naming constraint. The project should not contain any dots or other special characters. Otherwise, there will be a problem with the defined class structure in the codefile of the plugin.”
But these are quickly cleared up and the project then builds cleanly.
The plugin created by the template does have some basic functionality, it ties in to the OnDocumentComplete event and displays a “Hello World!” messagebox:
1: public Plugin() : base()
2: {
3: HostInstance = this;
4: this.OnDocumentComplete += Plugin_OnDocumentComplete;
5: }
6:
7: void Plugin_OnDocumentComplete(object pDisp, ref object url)
8: {
9: MessageBox.Show("Hello World!");
10: }
Building the project and executing the install batch file (which requires it be run as administrator), configures the plugin and now every page that loads within IE will say hello:
So that’s a basic little plugin, but what do I want to do with it? Well, being a playful and mischievous sort of fellow, I’ve decided to hijack MSDN.
So with a little event subscription and a couple lines of code, my plugin can now redirect any arrival at a MSDN URI right back here to my little blog:
1: public Plugin() : base()
2: {
3: HostInstance = this;
4: this.OnNavigateComplete += Plugin_OnNavigateComplete;
5: }
6:
7: void Plugin_OnNavigateComplete(object pDisp, ref object URL)
8: {
9: if (URL.ToString().StartsWith("http://msdn.microsoft.com"))
10: this.Navigate("http://www.lovethedot.net");
11: }
Imagine the fun we could have just by changing those URIs to something more interesting and installing this plugin on coworkers’ machines …
Okay, so fun, but not very useful, what else can we do? Really anything we might want to. The spicIE API includes a wealth of possibilities, including access to the page’s Document model. For instance, we could get a list of all the links on a page:
1: public Plugin() : base()
2: {
3: HostInstance = this;
4: this.OnDocumentComplete += Plugin_OnDocumentComplete;
5: }
6:
7: void Plugin_OnDocumentComplete(object pDisp, ref object url)
8: {
9: foreach (var item in DocumentProperties.LinkCollection)
10: {
11: MessageBox.Show(item);
12: }
13: }
(You’ll probably want to be careful where you run this little sample, or you’ll be clicking OK a lot.)
There’s a bit more involved if you want a user-interface (say a toolbar), but not much.
First create a user control and change it to inherit from SpicIE.Controls.Toolbar and there are two properties that must be overridden:
1: public override string PluginGuid
2: {
3: get
4: {
5: return "58AE4526-9474-4a80-A0CA-45BEFF07CEC9";
6: }
7: }
8:
9: public override string PluginProgID
10: {
11: get
12: {
13: return "LoveTheDot.PlugIn.IE.Toolbar1";
14: }
15: }
And some initialization to do in the constructor:
1: public Toolbar1()
2: {
3: InitializeComponent();
4:
5: this.ToolbarName = "Love the Dot Toolbar";
6: this.ToolbarTitle = "Love the Dot";
7:
8: this.ToolbarHelpText = "This is a very important toolbar";
9: this.ToolbarStyle = ToolbarEnum.ExplorerToolbar;
10:
11: // represents the startup size of the bar
12: this.Size = new Size(20, 20);
13: // represents the sizing steps
14: this.IntegralSize = new Size(0, 0);
15: // represents the minimum size
16: this.MinSize = new Size(20, 20);
17: // represents the maximum size
18: this.MaxSize = new Size(600, 600);
19:
20: // creates a new control collection and inserts the designer-generated controls
21: Control[] ctrls = new Control[Controls.Count];
22: Controls.CopyTo(ctrls, 0);
23:
24: // call internal method for implementing controls in the toolbar
25: BuildControls(ctrls);
26: }
There’s a region in the Plugin.cs class for registering UI controls:
1: #region Register your new browser UI elements here
2:
3: internal static List<SpicIE.Controls.IControlBase> RunOnceCOMRegistration()
4: {
5: Host.TraceSink.TraceEvent(TraceEventType.Information, 0,"RunOnceRegisterCOMControls");
6:
7: List<SpicIE.Controls.IControlBase> controls = new List<SpicIE.Controls.IControlBase>();
8:
9:
10:
11: return controls;
12: }
13:
14: #endregion
Just insert a line to add the new toolbar to the controls list:
1: controls.Add(new Toolbar1());
And it becomes available in the browser:
In this case, I gave my toolbar a title and a single button, which I’ll code now just by handling the Clicked event like I would any other button:
1: private void button1_Click(object sender, EventArgs e)
2: {
3: Plugin.HostInstance.Navigate("http://www.lovethedot.net");
4: }
The SpicIE.Host class, from which my Plugin descends, has a static method “HostInstance”, which gives access to the browser manipulation methods. So now clicking on the toolbar button navigates the current browser tab to http://www.lovethedot.net.
By allowing us to write Internet Explorer 7/8 browser plugins with managed code, spicIE opens a plugin development to a whole new group of developers.