How to get started with developing Internet Explorer extensions?
Asked Answered
D

11

208

Does anyone here have experience with/in developing IE extensions that can share their knowledge? This would include code samples, or links to good ones, or documentation on the process, or anything.

I really want to do this, but I'm hitting a giant wall with lousy documentation, lousy code/example code/lack thereof. Any help/resources you could offer would be greatly appreciated.

Specifically, I would like to start with how to get access to/manipulate the DOM from within a IE extension.

EDIT, even more details:

Ideally, I would like to plant a toolbar button that, when clicked, popped a menu up that contains links to external sites. I would also like to access the DOM and plant JavaScript on the page depending on some conditions.

What is the best way to persist information in an IE extension? In Firefox/Chrome/Most modern browsers, you use window.localStorage, but obviously with IE8/IE7, that's not an option. Maybe a SQLite DB or such? It is okay to assume that .NET 4.0 will be installed on a user's computer?

I don't want to use Spice IE as I want to build one that is compatible with IE9 as well. I've added the C++ tag to this question as well, because if it's better to build one in C++, I can do that.

Dregs answered 13/4, 2011 at 2:40 Comment(7)
IMHO IE 9 is orders of magnitude better than the previous versions. (Not that I'll leave Chrome for IE of course... not yet anyway.)Debrief
@Alex: what sort of things do you envision implementing in IE, so that we can start digging in the right general direction?Anchises
@Alex: In order to break this problem down into manageable pieces, i would need to know the following: can we assume that end-user will be running IE9 and will be willing to install dotNET 4.0 runtime?Anchises
I agree with GregC. Some more information will help here. Are you thinking on something like a toolbar, or maybe something that will pre-process what the user is browsing or something that will connect to a third party service.Pythian
@Anchises Optimally, you would like to exclude the fewest number of people. Forcing people to upgrade to IE9 is only marginally better than telling people that they have to use Chrome or FireFox. The suckage involved in supporting the older ie versions is the balancing act right? If IE9 is a two week project and IE8 is a 4 month project, it might be worthwhile to get a foot in the door quickly with IE9 and plan for a longer dev cycle until 8 s supported.Wahl
@Mehrdad and @GregC: What about IE9 specifically makes extension dev better then earlier versions of IE? There are lots of things better about IE, but what specifically applies here?Panfish
@Alex, take a look at Crossrider. It will make your life much easier.Page
R
230

[UPDATE] I'm updating this answer to work with Internet Explorer 11, in Windows 10 x64 with Visual Studio 2017 Community. The previous version of this answer (for Internet Explorer 8, in Windows 7 x64 and Visual Studio 2010) is at the bottom of this answer.

Creating a Working Internet Explorer 11 Add-on

I am using Visual Studio 2017 Community, C#, .Net Framework 4.6.1, so some of these steps might be slightly different for you.

You need to open Visual Studio as Administrator to build the solution, so that the post-build script can register the BHO (needs registry access).

Start by creating a class library. I called mine InternetExplorerExtension.

Add these references to the project:

  • Interop.SHDocVw: COM tab / search for "Microsoft Internet Controls"
  • Microsoft.mshtml: Assemblies tab / search for "Microsoft.mshtml"

Note: Somehow MSHTML was not registered in my system, even though I could find in in the Add Reference window. This caused an error while building:

Cannot find wrapper assembly for type library "MSHTML"

The fix can be found at http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html Or, you can run this batch script:

"%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
cd "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\PublicAssemblies"
regasm Microsoft.mshtml.dll
gacutil /i Microsoft.mshtml.dll

Create the following files:

IEAddon.cs

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32;
using mshtml;
using SHDocVw;

namespace InternetExplorerExtension
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("D40C654D-7C51-4EB3-95B2-1E23905C2A2D")]
    [ProgId("MyBHO.WordHighlighter")]
    public class WordHighlighterBHO : IObjectWithSite, IOleCommandTarget
    {
        const string DefaultTextToHighlight = "browser";

        IWebBrowser2 browser;
        private object site;

        #region Highlight Text
        void OnDocumentComplete(object pDisp, ref object URL)
        {
            try
            {
                // @Eric Stob: Thanks for this hint!
                // This was used to prevent this method being executed more than once in IE8... but now it seems to not work anymore.
                //if (pDisp != this.site)
                //    return;

                var document2 = browser.Document as IHTMLDocument2;
                var document3 = browser.Document as IHTMLDocument3;

                var window = document2.parentWindow;
                window.execScript(@"function FncAddedByAddon() { alert('Message added by addon.'); }");

                Queue<IHTMLDOMNode> queue = new Queue<IHTMLDOMNode>();
                foreach (IHTMLDOMNode eachChild in document3.childNodes)
                    queue.Enqueue(eachChild);

                while (queue.Count > 0)
                {
                    // replacing desired text with a highlighted version of it
                    var domNode = queue.Dequeue();

                    var textNode = domNode as IHTMLDOMTextNode;
                    if (textNode != null)
                    {
                        if (textNode.data.Contains(TextToHighlight))
                        {
                            var newText = textNode.data.Replace(TextToHighlight, "<span style='background-color: yellow; cursor: hand;' onclick='javascript:FncAddedByAddon()' title='Click to open script based alert window.'>" + TextToHighlight + "</span>");
                            var newNode = document2.createElement("span");
                            newNode.innerHTML = newText;
                            domNode.replaceNode((IHTMLDOMNode)newNode);
                        }
                    }
                    else
                    {
                        // adding children to collection
                        var x = (IHTMLDOMChildrenCollection)(domNode.childNodes);
                        foreach (IHTMLDOMNode eachChild in x)
                        {
                            if (eachChild is mshtml.IHTMLScriptElement)
                                continue;
                            if (eachChild is mshtml.IHTMLStyleElement)
                                continue;

                            queue.Enqueue(eachChild);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion
        #region Load and Save Data
        static string TextToHighlight = DefaultTextToHighlight;
        public static string RegData = "Software\\MyIEExtension";

        [DllImport("ieframe.dll")]
        public static extern int IEGetWriteableHKCU(ref IntPtr phKey);

        private static void SaveOptions()
        {
            // In IE 7,8,9,(desktop)10 tabs run in Protected Mode
            // which prohibits writes to HKLM, HKCU.
            // Must ask IE for "Writable" registry section pointer
            // which will be something like HKU/S-1-7***/Software/AppDataLow/
            // In "metro" IE 10 mode, tabs run in "Enhanced Protected Mode"
            // where BHOs are not allowed to run, except in edge cases.
            // see http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx
            IntPtr phKey = new IntPtr();
            var answer = IEGetWriteableHKCU(ref phKey);
            RegistryKey writeable_registry = RegistryKey.FromHandle(
                new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true)
            );
            RegistryKey registryKey = writeable_registry.OpenSubKey(RegData, true);

            if (registryKey == null)
                registryKey = writeable_registry.CreateSubKey(RegData);
            registryKey.SetValue("Data", TextToHighlight);

            writeable_registry.Close();
        }
        private static void LoadOptions()
        {
            // In IE 7,8,9,(desktop)10 tabs run in Protected Mode
            // which prohibits writes to HKLM, HKCU.
            // Must ask IE for "Writable" registry section pointer
            // which will be something like HKU/S-1-7***/Software/AppDataLow/
            // In "metro" IE 10 mode, tabs run in "Enhanced Protected Mode"
            // where BHOs are not allowed to run, except in edge cases.
            // see http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx
            IntPtr phKey = new IntPtr();
            var answer = IEGetWriteableHKCU(ref phKey);
            RegistryKey writeable_registry = RegistryKey.FromHandle(
                new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true)
            );
            RegistryKey registryKey = writeable_registry.OpenSubKey(RegData, true);

            if (registryKey == null)
                registryKey = writeable_registry.CreateSubKey(RegData);
            registryKey.SetValue("Data", TextToHighlight);

            if (registryKey == null)
            {
                TextToHighlight = DefaultTextToHighlight;
            }
            else
            {
                TextToHighlight = (string)registryKey.GetValue("Data");
            }
            writeable_registry.Close();
        }
        #endregion

        [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
        [InterfaceType(1)]
        public interface IServiceProvider
        {
            int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
        }

        #region Implementation of IObjectWithSite
        int IObjectWithSite.SetSite(object site)
        {
            this.site = site;

            if (site != null)
            {
                LoadOptions();

                var serviceProv = (IServiceProvider)this.site;
                var guidIWebBrowserApp = Marshal.GenerateGuidForType(typeof(IWebBrowserApp)); // new Guid("0002DF05-0000-0000-C000-000000000046");
                var guidIWebBrowser2 = Marshal.GenerateGuidForType(typeof(IWebBrowser2)); // new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
                IntPtr intPtr;
                serviceProv.QueryService(ref guidIWebBrowserApp, ref guidIWebBrowser2, out intPtr);

                browser = (IWebBrowser2)Marshal.GetObjectForIUnknown(intPtr);

                ((DWebBrowserEvents2_Event)browser).DocumentComplete +=
                    new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
            }
            else
            {
                ((DWebBrowserEvents2_Event)browser).DocumentComplete -=
                    new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
                browser = null;
            }
            return 0;
        }
        int IObjectWithSite.GetSite(ref Guid guid, out IntPtr ppvSite)
        {
            IntPtr punk = Marshal.GetIUnknownForObject(browser);
            int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite);
            Marshal.Release(punk);
            return hr;
        }
        #endregion
        #region Implementation of IOleCommandTarget
        int IOleCommandTarget.QueryStatus(IntPtr pguidCmdGroup, uint cCmds, ref OLECMD prgCmds, IntPtr pCmdText)
        {
            return 0;
        }
        int IOleCommandTarget.Exec(IntPtr pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
            try
            {
                // Accessing the document from the command-bar.
                var document = browser.Document as IHTMLDocument2;
                var window = document.parentWindow;
                var result = window.execScript(@"alert('You will now be allowed to configure the text to highlight...');");

                var form = new HighlighterOptionsForm();
                form.InputText = TextToHighlight;
                if (form.ShowDialog() != DialogResult.Cancel)
                {
                    TextToHighlight = form.InputText;
                    SaveOptions();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return 0;
        }
        #endregion

        #region Registering with regasm
        public static string RegBHO = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects";
        public static string RegCmd = "Software\\Microsoft\\Internet Explorer\\Extensions";

        [ComRegisterFunction]
        public static void RegisterBHO(Type type)
        {
            string guid = type.GUID.ToString("B");

            // BHO
            {
                RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegBHO, true);
                if (registryKey == null)
                    registryKey = Registry.LocalMachine.CreateSubKey(RegBHO);
                RegistryKey key = registryKey.OpenSubKey(guid);
                if (key == null)
                    key = registryKey.CreateSubKey(guid);
                key.SetValue("Alright", 1);
                registryKey.Close();
                key.Close();
            }

            // Command
            {
                RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegCmd, true);
                if (registryKey == null)
                    registryKey = Registry.LocalMachine.CreateSubKey(RegCmd);
                RegistryKey key = registryKey.OpenSubKey(guid);
                if (key == null)
                    key = registryKey.CreateSubKey(guid);
                key.SetValue("ButtonText", "Highlighter options");
                key.SetValue("CLSID", "{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}");
                key.SetValue("ClsidExtension", guid);
                key.SetValue("Icon", "");
                key.SetValue("HotIcon", "");
                key.SetValue("Default Visible", "Yes");
                key.SetValue("MenuText", "&Highlighter options");
                key.SetValue("ToolTip", "Highlighter options");
                //key.SetValue("KeyPath", "no");
                registryKey.Close();
                key.Close();
            }
        }

        [ComUnregisterFunction]
        public static void UnregisterBHO(Type type)
        {
            string guid = type.GUID.ToString("B");
            // BHO
            {
                RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegBHO, true);
                if (registryKey != null)
                    registryKey.DeleteSubKey(guid, false);
            }
            // Command
            {
                RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegCmd, true);
                if (registryKey != null)
                    registryKey.DeleteSubKey(guid, false);
            }
        }
        #endregion
    }
}

Interop.cs

using System;
using System.Runtime.InteropServices;
namespace InternetExplorerExtension
{
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")]
    public interface IObjectWithSite
    {
        [PreserveSig]
        int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site);
        [PreserveSig]
        int GetSite(ref Guid guid, [MarshalAs(UnmanagedType.IUnknown)]out IntPtr ppvSite);
    }


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct OLECMDTEXT
    {
        public uint cmdtextf;
        public uint cwActual;
        public uint cwBuf;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public char rgwz;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct OLECMD
    {
        public uint cmdID;
        public uint cmdf;
    }

    [ComImport(), ComVisible(true),
    Guid("B722BCCB-4E68-101B-A2BC-00AA00404770"),
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IOleCommandTarget
    {

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int QueryStatus(
            [In] IntPtr pguidCmdGroup,
            [In, MarshalAs(UnmanagedType.U4)] uint cCmds,
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref OLECMD prgCmds,
            //This parameter must be IntPtr, as it can be null
            [In, Out] IntPtr pCmdText);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int Exec(
            //[In] ref Guid pguidCmdGroup,
            //have to be IntPtr, since null values are unacceptable
            //and null is used as default group!
            [In] IntPtr pguidCmdGroup,
            [In, MarshalAs(UnmanagedType.U4)] uint nCmdID,
            [In, MarshalAs(UnmanagedType.U4)] uint nCmdexecopt,
            [In] IntPtr pvaIn,
            [In, Out] IntPtr pvaOut);
    }
}

and finally a form, that we will use to configure the options. In this form place a TextBox and an Ok Button. Set the DialogResult of the button to Ok. Place this code in the form code:

using System.Windows.Forms;
namespace InternetExplorerExtension
{
    public partial class HighlighterOptionsForm : Form
    {
        public HighlighterOptionsForm()
        {
            InitializeComponent();
        }

        public string InputText
        {
            get { return this.textBox1.Text; }
            set { this.textBox1.Text = value; }
        }
    }
}

In the project properties, do the following:

  • Sign the assembly with a strong-key;
  • In the Debug tab, set Start External Program to C:\Program Files (x86)\Internet Explorer\iexplore.exe
  • In the Debug tab, set Command Line Arguments to http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
  • In the Build Events tab, set Post-build events command line to:

    "%ProgramFiles(x86)%\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
    
    "%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
    
    "%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"

Attention: even though my computer is x64, I used the path of the non-x64 gacutil.exe and it worked... the one specific for x64 is at:

C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\gacutil.exe

64bit IE Needs 64bit-compiled and 64bit-registered BHO. Though I could only debug using 32bit IE11, the 32bit registered extension also worked by running 64bit IE11.

This answer appears to have some additional info about this: https://mcmap.net/q/129055/-developing-internet-explorer-browser-helper-object-extensions

If you need to, you can use the 64bit regasm:

%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe

How this add-on works

I didn't change the behavior of the add-on... take a look at IE8 section bellow for description.


## Previous Answer for IE8

Man... this has been a lot of work! I was so curious about how to do this, that I did it myself.

First of all... credit is not all mine. This is a compilation of what I found, on these sites:

And of course, I wanted my answer to have the features you asked:

  • DOM traversal to find something;
  • a button that shows a window (in my case to setup)
  • persist the configuration (I will use registry for that)
  • and finally execute javascript.

I will describe it step by step, how I managed to do it working with Internet Explorer 8, in Windows 7 x64... note that I could not test in other configurations. Hope you understand =)

Creating a Working Internet Explorer 8 Add-on

I am using Visual Studio 2010, C# 4, .Net Framework 4, so some of these steps might be slightly different for you.

Created a class library. I called mine InternetExplorerExtension.

Add these references to the project:

  • Interop.SHDocVw
  • Microsoft.mshtml

Note: These references may be in different places in each computer.

this is what my references section in csproj contains:

<Reference Include="Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyToken=90ba9c70f846762e, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <EmbedInteropTypes>True</EmbedInteropTypes>
  <HintPath>C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Interop.SHDocVw.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
  <EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />

Create the files the same way as the updated IE11 files.

IEAddon.cs

You can uncomment the following lines from IE11 version:

...
// @Eric Stob: Thanks for this hint!
// This was used to prevent this method being executed more than once in IE8... but now it seems to not work anymore.
if (pDisp != this.site)
    return;
...

Interop.cs

Same as IE11 version.

and finally a form, that we will use to configure the options. In this form place a TextBox and an Ok Button. Set the DialogResult of the button to Ok. The code is the same for IE11 addon.

In the project properties, do the following:

  • Sign the assembly with a strong-key;
  • In the Debug tab, set Start External Program to C:\Program Files (x86)\Internet Explorer\iexplore.exe
  • In the Debug tab, set Command Line Arguments to http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
  • In the Build Events tab, set Post-build events command line to:

    "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
    
    "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
    
    "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"

Attention: as my computer is x64, there is a specific x64 inside the path of gacutil executable on my machine that may be different on yours.

64bit IE Needs 64bit-compiled and 64bit-registered BHO. Use 64bit RegAsm.exe (usually lives in C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe)

How this add-on works

It traverses all DOM tree, replacing the text, configured using the button, by itself with a yellow background. If you click on the yellowed texts, it calls a javascript function that was inserted on the page dynamically. The default word is 'browser', so that it matches a lot of them! EDIT: after changing the string to be highlighted, you must click the URL box and press Enter... F5 will not work, I think that it is because F5 is considered as 'navigation', and it would require to listen to navigate event (maybe). I'll try to fix that later.

Now, it is time to go. I am very tired. Feel free to ask questions... may be I will not be able to answer since I am going on a trip... in 3 days I'm back, but I'll try to come here in the meantime.

Reposeful answered 21/4, 2011 at 5:37 Comment(25)
Hi, I did exactly what is described in the answer. The button is appearing. The exec funtion is exectued. However, SetSite and GetSite functions are never called. I wanna be able to know the URL of the page I am on. It's failing to call these methods to initialize the browser.. Please helpRorke
I tried to do this on IE9 and: 1. If your project path has spaces: instead of $(TargetDir)$(TargetFileName) use "$(TargetDir)$(TargetFileName)" 2. If you use Visual Studio 2010 Express you probably (I do) don't see the Start External Program option in Debug tab - I simply run IE and navigate to the provided URL 3. It seems not to work on IE9 - I can open the form (Highlighter options) but I don't know how to make it highlight the textDissenter
For the Interop.SHDocVw reference - instead you should add a COM reference to "Microsoft Internet Controls" and then "using SHDocVw;"Orthotropic
Then also you will need Microsoft.VisualStudio.OLE.Interop.dll from the GAC. (for IObjectWithSite etc)Orthotropic
OK since this thread has helped me SOOO much, I want to contribute a little. 1) if you are going to try to regiser a search provider, do it in the RegisterBHO function which will be run with user-level permissions. 2) DocumentComplete is called for every frame in the page (often 5-10 per actual document) You should add code in SetSite() this.site = site; and in OnDocumentComplete() if (pDisp != site) return; this will cause it to only run when the document is in fact complete. (attribution: Pro Internet Explorer 8 & 9 Development by Matthew Crowley)Orthotropic
@Eric Stob: Thanks for the hint on OnDocumentComplete() if (pDisp != site) return;... edited the answer already. Sorry for the loooong delay. Now the sample addin is working much better!Reposeful
@mustafabar: Hi! Don't know if you need help anymore, since it has been soooo much time since you asked for, but I changed this sample to allow you to access the browser object from the Exec method, just like you asked.Reposeful
@MiguelAngelo Why is revision 9 of your answer more "correct"? I'm referring to the transition of the single line browser = (IWebBrowser2)site; to IServiceProvider, in particular.Dirichlet
@RobW: It is not more "correct"... Microsoft documentation states that the correct way of getting a IWebBrowser2 interface is by using the IServiceProvider interface. When in the context of a command-bar, the site is not a IWebBrowser2, and the type cast fails.Reposeful
I have not tried your code. I've found this extension on Github (by dvdotsenko), which is heavily based on an old revision of your answer. After polishing his implementation, creating build scripts, etc, I tested the extension, which seemed to work. After that, I decided to implement it in C++ (instead of C# + .NET), because I saw many claims that C#+.NET is significantly slower.Dirichlet
@RobW: in fact HBOs made in C# have a huge load time, because it needs to load 30~40MB of .Net libraries into the browser memory.Reposeful
FYI, MSDN reference supporting Eric's comment about pDisp != site: support.microsoft.com/kb/180366 "The top-level frame fires the DocumentComplete in the end. So, to check if a page is done downloading, you need to check if the IDispatch* parameter is same as the IDispatch of the WebBrowser control"Dirichlet
"IE10 on x64 Windows 8 will not load your add-on when starting unless you will build with "Any CPU" architecture and register using both 32 and 64 bit RegAsm.exe." was an edit by someone that got rejected.Calliper
Hi all, when I click on add ons button, i want to create small popup window below button, that will contain some HTML. By clicking add ons button in toolbar code will run this method IOleCommandTarget.Exec(IntPtr pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut). How to get button position info, so I can know where to locate my popup?ThanksContreras
...and what do you think what approach would be best to create popup, windows form? Popup should look like tooltip below button and it should apper when user click on button and dissapear when it click again.Contreras
IE11 on x64 Windows 7 this is not working, i did exactly like mentioned over and over spending 1 week. but in IE11 its not working at all. Can anyone please check how ot make it IE11 compatible and make it 64-bit?Tepefy
IE11 on Windows 7 64-bit, i used 1) 64bit RegAsm.exe 2) also build with "Any CPU" platform 3) Also used latest Visual studio 2013 , but still its not working. Anyone please ???Tepefy
IE11 on Windows 7 64-bit, this is not working can anyone help?Tepefy
Please see the follow up: #22954071Tepefy
After reviewing a lot of comments, I believe its not possible to create an IE extension without use of .NET. But a small doubt probably silly too.. is it also necessary that the system that installs this plugin must have .NET framework installed on his system? Although all the library files will be present within the solutionMond
If anyone is running into issues. I suggest turning on Detailed verbosity for msbuild and checking for whether GAC Utility was able to successfully register the assembly. If not, try changing to a newer Windows SDK version of GAC (e.g. I needed to use C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\x64 (Windows 10 version of GAC)Photobathic
@MiguelAngelo thanks for this answer! I tried the above mentioned steps and could register the BHO successfully. The add-on is visible within IE11 as well and can be enabled. Although it doesn't seem to be effective. My current setup is .NET Framework 4, Windows 10, IE 11, I've built for x86. I'm currently trying to get the following sample add-on to work on my machine codeproject.com/Articles/149258/… Thank you!Ecclesiastic
cppwinrt is made to tackle this kind of epic win mess, and is apparently sucesfull. Is there anybody who can show us the cppwinrt way?Phasia
@MiguelAngelo Thanks a lot for this answer. I am able to setup on windows 10 using VS 2015 community. I am able to see addon inside IE. but the issue is its only working when started from VS instance that is given on DEBUG->Start External Program . But if I manually start IE instance , its not working although I could see addon loaded time is changing when I am refreshing a page.Why so ? How to make this addon to work with IE instance alone , not the IE instance from VS.Please help !!!Gaven
@MiguelAngelo Can you please help me on the above issue ?Gaven
P
12

The state for IE extensions is actually pretty sad. You have the old model of IE5 Browser Helper Object (yeah, those infamous BHOs that everyone liked to block back in the day), toolbars and the new accelerators for IE. Even then, compatibility will break sometimes. I used to maintain an extension for IE6 that broke with IE7, so there are some things that have changed. For the most part, as far as I know (I haven't touch BHOs in years) you still need to code them using Active Template Libraries (kind of like an STL for Microsoft's COM) and well as such is only for C++. You could do COM Interop with C# and get away with doing it in C# but its probably going to be too hard for what it is worth. Anyway, if you are interested in coding your own extension for IE (which is plausible if you want to have your extensions available in all major browsers) here are the official Microsoft Resources.

http://msdn.microsoft.com/en-us/library/aa753587(v=vs.85).aspx

And for the accelerators that are new in IE8 you could check this one.

http://msdn.microsoft.com/en-us/library/cc289775(v=vs.85).aspx

I agree the documentation is terrible, and the APIs are quite outdated. Still I hope this helps.

EDIT: I guess I can throw one last source of information here. I was looking through my notes of back when I was working on BHOs. And this is the article that got me started with them. It is kind of old, but has a good explanation of the ATL interfaces that you will be using when working with IE BHOs (IObjectWithSite for example). I think it is pretty well explained and helped me a lot back then. http://msdn.microsoft.com/en-us/library/bb250436.aspx I also checked the example that GregC posted. It does work with at least IE8, and it is compatible with VS 2010, so if you want to do C# you can get started there and take a look at Jon Skeet's Book. (C# in Depth 2nd edition) Chapter 13 has a good deal of information about the new features in C# 4 that you can use to make the interaction with COM nicer. (I would still recommend you doing your addin in C++)

Pythian answered 13/4, 2011 at 16:44 Comment(0)
C
12

Another cool approach would be to check out:

http://www.crossrider.org

It's a framework based on JS with jquery which lets you develop browsers extensions for IE, FF and Chrome using a single common JS code. Basically the framework does all the nasty work and you're left with writing your applications code.

Clamworm answered 12/12, 2011 at 15:57 Comment(1)
Yeah, this really is the way to go, as well avoiding the nightmare that is developing a plugin in visual studio it means you only have to write your plugin once for all browsers. It also means not having to develop in a virtual machine if you're a mac user.Dorsoventral
S
6

Developing C# BHOs is a pain-in-the-arse. It involves a lot of icky COM code and p/invoke calls.

I have a mostly finished C# BHO here, which you are free to use the source for whatever you want. I say "mostly", because I never did figure out how to save appdata under IE Protected Mode.

Salami answered 16/4, 2011 at 3:51 Comment(4)
C# 4.0 might be better in this regard, as the COM Interop is much improved.Leucomaine
@Robert: Really? I had no idea... what are the differences?Debrief
@Mehrdad: You can get a taste of the differences here: devx.com/dotnet/Article/42590/1954. For a more in-depth discussion, see Anders Hejlsberg's talk, "The Future of C#," here: channel9.msdn.com/Blogs/pdc2008/TL16Leucomaine
@Robert @Mehrdad: Not really. It is not the COM interop that is icky (in this respect), it is developing and registering a COM module, which the new C# 4.0 features don't help with.Salami
U
4

I've been working with IE's webbrowser control for years now, and over the course of them, one name comes up over and over again with helpful postings: Igor Tandetnik

If I were developing an extension, I would target a BHO, and start googling for:

BHO Igor Tandetnik

OR

Browser Helper Object Igor Tandetnik

His postings are often very detailed, and he knows what he is talking about.

You're going to find yourself up to your ears in COM and ATL programming. For a sample walkthrough, check out: http://msdn.microsoft.com/en-us/library/ms976373.aspx

Ukrainian answered 16/4, 2011 at 3:55 Comment(1)
The biggest downside to using C# (which is the direction that most of the other posters are going) is that it's going to be going through all sorts of extra layers, with workaround and patches for code that would be native to C++.Ukrainian
A
3

I agree with Robert Harvey, C# 4.0 features improved COM interop. Here's a bit of older C# code, in desperate need of a re-write.

http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx

This is an attempt to simplify things by avoiding ATL and going with Spartan COM:

C++ and COM to get BHOs going

Anchises answered 16/4, 2011 at 4:22 Comment(0)
P
3

If you are not trying to reinvent the wheel, you might try Add In Express for IE . I have used the product for the VSTO stuff, and its pretty good. Also they have a helpful forum and quick support.

Postern answered 19/4, 2011 at 8:29 Comment(0)
A
3

It is obviously solved, but for the other users, I would recommend SpicIE framework. I have made my own extension based on it. It only supports Internet Explorer 7/8 officialy, but I tested that on Internet Explorer 6-10 (from Windows XP to Windows 8 Consumer Preview) and it works fine. Unfortunately there were some bugs in the latest release, so I had to fix them and made my own release: http://archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251

Arathorn answered 4/5, 2012 at 23:5 Comment(0)
M
0

I warmly suggest you this post of Pavel Zolnikov published in 2002!

http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and

It is based on the use of Band objects and is compiled using .Net 2.0. Source code is provided and opens and compiles well with Visual Studio 2013. As you will read on the post comments it works perfectly well for IE 11 and on Windows 7 and Windows 10. It worked perfectly well for me on Windows 7 + SP1 and IE 11 Enjoy!

Malapropos answered 7/9, 2016 at 12:53 Comment(1)
We like answers to be self contained on StackOverflow. All this post really tells me is "use Band objects and .Net 2.0". Could you include some sample code here to show how it could be done?Gigantean
B
0

The question is from 2013, now it's 2020, but it may be helpful for future visitors.

I tried to implement @Miguel Angelo's answer, it didn't worked at the beginning.

There still some settings that you be defined.

on internet explorer (I'm using IE-11) go to Tools-->Internet Options-->Advanced: enter image description here

enter image description here

Also see this SO question and this example from github

Bidget answered 20/2, 2020 at 8:45 Comment(0)
F
-2

enter image description here

In the Build Events tab, set Post-build events command line to: (x64) is listed below

"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /if "$(TargetDir)$(TargetFileName)"    
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" /u "$(TargetDir)$(TargetFileName)"    
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"

I want the Build Events tab , set Post-build events command line to (32 bit operating system)

"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\gacutil.exe" /if "$(TargetDir)$(TargetFileName)"    
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /u "$(TargetDir)$(TargetFileName)"    
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
Floorboard answered 26/7, 2013 at 7:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.