如何开始开发Internet Explorer扩展?

有没有人在这里有开发可扩展知识的IE扩展的经验? 这将包括代码示例,或者链接到好的,或者关于这个过程的文档,或者其他任何东西。

我真的很想这样做,但是我正在用一个糟糕的文档,糟糕的代码/示例代码/缺少的巨大墙壁。 任何帮助/资源你可以提供将不胜感激。

具体来说,我想从如何从IE扩展中访问/操作DOM开始。

编辑,甚至更多的细节:

理想情况下,我想种植一个工具栏按钮,点击后会弹出一个菜单,其中包含指向外部网站的链接。 我还想根据某些条件访问DOM并在页面上植入JavaScript。

在IE扩展中保存信息的最佳方式是什么? 在Firefox / Chrome /大多数现代浏览器中,使用window.localStorage ,但显然使用IE8 / IE7,这不是一个选项。 也许一个SQLite数据库或这样的? 假设.NET 4.0将安装在用户的计算机上是可以的吗?

我不想使用Spice IE,因为我想构建一个与IE9兼容的IE。 我也为这个问题添加了C ++标签,因为如果最好在C ++中构建一个,我可以做到这一点。


男人......这已经很多工作了! 我很好奇如何做到这一点,我自己做到了。

首先...信贷并不全是我的。 这是我在这些网站上发现的一个汇编:

  • CodeProject的文章,如何制作BHO;
  • 15秒,但不是15秒,花了大约7个小时;
  • 微软教程,帮助我添加命令按钮。
  • 而这个social.msdn话题,帮助我弄清楚该程序集必须在GAC中。
  • 这个最近的MSDN博客文章包含一个完整的示例
  • 许多其他网站,在发现过程中...
  • 当然,我想让我的答案有你提到的功能:

  • DOM遍历来找到某些东西;
  • 一个显示窗口的按钮(在我的情况下设置)
  • 坚持配置(我将使用regitry)
  • 并最终执行JavaScript。
  • 我将逐步描述它,我如何在Windows 7 x64中设法使用Internet Explorer 8来处理它...请注意,我无法在其他配置中进行测试。 希望你明白=)

    创建一个可用的Internet Explorer 8插件

    我使用的是Visual Studio 2010C#4.Net Framework 4 ,因此其中一些步骤可能会略有不同。

    创建了一个类库。 我打电话给我的InternetExplorerExtension。

    将这些引用添加到项目中:

  • Interop.SHDocVw
  • Microsoft.mshtml
  • 注意:这些引用可能位于每台计算机的不同位置。

    这是我在csproj中的引用部分包含的内容:

    <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.0Common7IDEPrivateAssembliesInterop.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" />
    

    创建以下文件:

    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 will prevent this method being executed more than once.
                    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 = "SoftwareMyIEExtension";
    
            [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 = "SoftwareMicrosoftWindowsCurrentVersionExplorerBrowser Helper Objects";
            public static string RegCmd = "SoftwareMicrosoftInternet ExplorerExtensions";
    
            [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);
        }
    }
    

    最后是一个表单,我们将用它来配置选项。 在这个表单中放置一个TextBox和一个Ok Button 。 将按钮的DialogResult设置为Ok 。 将此代码放置在表单代码中:

    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; }
            }
        }
    }
    

    在项目属性中,执行以下操作:

  • 用强大的钥匙在大会上签名;
  • 在调试选项卡中,将启动外部程序设置为C:Program Files (x86)Internet Exploreriexplore.exe
  • 在调试选项卡中,将命令行参数设置为http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
  • 在“构建事件”选项卡中,将后构建事件命令行设置为:

    "C:Program Files (x86)Microsoft SDKsWindowsv7.0ABinNETFX 4.0 Toolsx64gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
    
    "C:WindowsMicrosoft.NETFrameworkv4.0.30319RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
    
    "C:WindowsMicrosoft.NETFrameworkv4.0.30319RegAsm.exe" "$(TargetDir)$(TargetFileName)"
  • 注意:由于我的计算机是x64,我的机器上gacutil可执行文件的路径中有一个特定的x64,可能与您的计算机不同。

    64位IE需要64位编译和64位注册的BHO。 使用64位RegAsm.exe(通常位于C: Windows Microsoft.NET Framework64 v4.0.30319 RegAsm.exe中)

    这个插件如何工作

    它遍历所有DOM树,替换使用按钮配置的文本,本身带有黄色背景。 如果您单击黄色文本,它会调用插入到页面上的JavaScript函数。 默认的单词是'浏览器',所以它匹配很多! 编辑:改变字符串后要突出显示,你必须单击URL框并按Enter ... F5将无法正常工作,我认为这是因为F5被认为是'导航',并且它将需要监听导航事件(也许)。 我会尽力在稍后解决。

    现在,该走了。 我很累。 随意提问...可能是因为我正在旅行,我无法回答...在3天内我回来了,但我会尽力在此期间来这里。


    另一个很酷的方法是检查:

    http://www.crossrider.org

    这是一个基于JS和jQuery的框架,它允许您使用一个常见的JS代码为IE,FF和Chrome开发浏览器扩展。 基本上,框架完成所有恶劣的工作,而您只需编写应用程序代码。


    IE扩展的状态实际上很让人伤心。 你有旧的IE5浏览器帮助对象模型(是的,那些臭名昭着的BHO,每个人都喜欢在白天阻止),工具栏和IE的新加速器。 即便如此,兼容性有时也会中断。 我曾经为IE6打破IE7的扩展,所以有些事情已经改变了。 大部分情况下,据我所知(我多年来没有碰到BHO),你仍然需要使用活动模板库(类似于微软的COM的STL)对它们进行编码,以及仅适用于C ++。 你可以用C#做​​COM Interop,并且可以在C#中完成它,但它可能对于它的价值来说太难了。 无论如何,如果您有兴趣编写您自己的IE扩展程序(如果您希望在所有主流浏览器中都可以使用扩展程序,这是合理的),这里是官方的Microsoft资源。

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

    对于IE8中的新加速器,您可以检查这一个。

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

    我同意这些文档很糟糕,而且API太过时了。 但我希望这有助于。

    编辑:我想我可以在这里扔最后一个信息来源。 当我在BHO工作时,我正在浏览笔记。 这是让我从他们开始的文章。 它有点古怪,但是对使用IE浏览器BHO(例如IObjectWithSite)时将使用的ATL接口有很好的解释。 我认为这个解释很好,当时帮了我很多。 http://msdn.microsoft.com/en-us/library/bb250436.aspx我也检查了GregC发布的示例。 它至少可以与IE8一起工作,并且与VS 2010兼容,所以如果你想做C#,你可以开始在那里看看Jon Skeet的书。 (C#深入第2版)第13章有大量有关C#4中新特性的信息,您可以使用它们与COM进行更好的交互。 (我仍然建议你用C ++来做你的插件)

    链接地址: http://www.djcxy.com/p/40225.html

    上一篇: How to get started with developing Internet Explorer extensions?

    下一篇: Algorithm challenge to merge sets