【问题标题】:How to get started with developing Internet Explorer extensions?如何开始开发 Internet Explorer 扩展?
【发布时间】:2011-08-04 08:51:25
【问题描述】:

这里有没有人在开发 IE 扩展方面有经验,可以分享他们的知识?这将包括代码示例,或指向优秀示例的链接,或有关流程的文档,或任何内容。

我真的很想这样做,但我遇到了糟糕的文档、糟糕的代码/示例代码/缺少这些的巨大墙壁。非常感谢您提供的任何帮助/资源。

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

编辑,更多细节:

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

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

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

【问题讨论】:

  • 恕我直言 IE 9 比以前的版本好几个数量级。 (当然不是说我会把 Chrome 留在 IE 上……反正现在还没有。)
  • @Alex:你设想在 IE 中实现什么样的东西,以便我们可以开始朝正确的大方向进行挖掘?
  • @Alex:为了将这个问题分解成可管理的部分,我需要知道以下几点:我们是否可以假设最终用户将运行 IE9 并愿意安装 dotNET 4.0 运行时?
  • 我同意 GregC。更多信息将在这里有所帮助。您是否正在考虑工具栏之类的东西,或者可能会预处理用户正在浏览的内容或将连接到第三方服务的东西。
  • @Alex,看看Crossrider。它会让你的生活更轻松。

标签: c# c++ internet-explorer atl browser-extension


【解决方案1】:

[更新] 我正在更新此答案,以便在 Windows 10 x64 中与 Visual Studio 2017 社区 一起使用 Internet Explorer 11。 此答案的先前版本(适用于 Internet Explorer 8,在 Windows 7 x64 和 Visual Studio 2010 中)位于此答案的底部。

创建一个正常工作的 Internet Explorer 11 插件

我正在使用 Visual Studio 2017 CommunityC#.Net Framework 4.6.1,因此其中一些步骤可能会略有不同给你。

您需要以管理员身份打开 Visual Studio 来构建解决方案,以便构建后脚本可以注册 BHO(需要注册表访问权限)。

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

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

  • Interop.SHDocVw:COM 选项卡/搜索"Microsoft Internet Controls"
  • Microsoft.mshtml:“程序集”选项卡/搜索 "Microsoft.mshtml"

注意: 不知何故,MSHTML 没有在我的系统中注册,即使我可以在“添加引用”窗口中找到。这在构建时导致错误:

找不到类型库“MSHTML”的包装程序集

可以在http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html 找到修复程序 或者,您可以运行此批处理脚本:

"%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

创建以下文件:

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

最后是一个表单,我们将使用它来配置选项。在此表单中放置 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 Explorer\iexplore.exe
  • 在“调试”选项卡中,将 命令行参数 设置为 http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
  • 在构建事件选项卡中,将构建后事件命令行设置为:

    "%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" /注销 "$(TargetDir)$(TargetFileName)"
    
    "%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"

注意:虽然我的电脑是 x64,但我使用了非 x64 的路径 gacutil.exe 并且它有效... x64 专用的路径是:

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

64 位 IE 需要 64 位编译和 64 位注册的 BHO。虽然我只能使用 32 位 IE11 进行调试,但 32 位注册扩展也可以通过运行 64 位 IE11 来工作。

这个答案似乎有一些关于这个的附加信息:https://stackoverflow.com/a/23004613/195417

如果需要,可以使用 64bit regasm:

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

此插件的工作原理

我没有更改插件的行为...请查看下面的 IE8 部分进行说明。


## IE8 的上一个答案

伙计……这是一项艰巨的工作! 我很好奇如何做到这一点,所以我自己做了。

首先...功劳不全是我的。这是我在这些网站上找到的内容的汇编:

当然,我希望我的答案具有您所要求的功能:

  • DOM 遍历以找到某些东西;
  • 一个显示窗口的按钮(在我的例子中是设置)
  • 保留配置(我将使用注册表)
  • 最后执行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.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" />

以与更新的 IE11 文件相同的方式创建文件。

IEAddon.cs

您可以在 IE11 版本中取消注释以下行:

...
// @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

同IE11版本。

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

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

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

    "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /f /i "$(TargetDir) $(目标文件名)"
    
    "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /注销 "$(TargetDir)$(TargetFileName)"
    
    "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.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天后我回来了,但我会尝试在此期间来这里。

【讨论】:

  • 嗨,我完全按照答案中的描述做了。按钮出现。 exec 函数被执行。但是,永远不会调用 SetSite 和 GetSite 函数。我希望能够知道我所在页面的 URL。无法调用这些方法来初始化浏览器..请帮助
  • 我尝试在 IE9 上执行此操作并且:1. 如果您的项目路径有空格:使用 $(TargetDir)$(TargetFileName) 而不是 "$(TargetDir)$(TargetFileName)" 2. 如果您使用 Visual Studio 2010 Express,您可能(我愿意)在调试选项卡中看不到 启动外部程序 选项 - 我只是运行 IE 并导航到提供的 URL 3。它似乎不适用于 IE9 - 我可以打开表单(荧光笔选项),但我不知道如何使其突出显示文本
  • 对于 Interop.SHDocVw 参考 - 您应该添加对“Microsoft Internet Controls”的 COM 参考,然后“使用 SHDocVw;”
  • “x64 Windows 8 上的 IE10 在启动时不会加载您的插件,除非您将使用“任何 CPU”架构构建并使用 32 位和 64 位 RegAsm.exe 进行注册。”是被拒绝的人的编辑。
【解决方案2】:

IE 扩展的状态实际上是相当可悲的。您拥有旧模型的 IE5 浏览器帮助对象(是的,那些臭名昭著的 BHO,过去每个人都喜欢阻止)、工具栏和 IE 的新加速器。 即使那样,兼容性有时也会中断。我曾经维护一个与 IE7 中断的 IE6 扩展,所以有些东西已经改变了。在大多数情况下,据我所知(我已经很多年没有接触过 BHO),您仍然需要使用活动模板库(有点像 Microsoft 的 COM 的 STL)对它们进行编码,并且仅适用于 C++。 你可以用 C# 做 COM 互操作,然后用 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 时将使用的 ATL 接口(例如 IObjectWithSite)。我认为它解释得很好,当时对我有很大帮助。 http://msdn.microsoft.com/en-us/library/bb250436.aspx 我还检查了 GregC 发布的示例。它至少适用于 IE8,并且与 VS 2010 兼容,所以如果你想做 C#,你可以从那里开始,看看 Jon Skeet 的书。 (C# in Depth 第 2 版)第 13 章有大量关于 C# 4 中新特性的信息,您可以使用这些新特性来更好地与 COM 交互。 (我仍然建议你用 C++ 做你的插件)

【讨论】:

    【解决方案3】:

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

    http://www.crossrider.org

    它是一个基于 JS 和 jquery 的框架,可让您使用单个通用 JS 代码为 IE、FF 和 Chrome 开发浏览器扩展。 基本上框架会完成所有令人讨厌的工作,而您只需要编写应用程序代码即可。

    【讨论】:

    • 是的,这确实是要走的路,同时避免了在 Visual Studio 中开发插件的噩梦,这意味着您只需为所有浏览器编写一次插件。这也意味着如果您是 mac 用户,则不必在虚拟机中进行开发。
    【解决方案4】:

    开发 C# BHO 是一件令人头疼的事情。它涉及大量令人讨厌的 COM 代码和 p/invoke 调用。

    我有一个基本完成的 C# BHO here,你可以随意使用 the source 来做任何你想做的事情。我说“大部分”,因为我从来不知道如何save appdata under IE Protected Mode

    【讨论】:

    • C# 4.0 在这方面可能会更好,因为 COM 互操作性得到了很大改进。
    • @罗伯特:真的吗?我不知道...有什么区别?
    • @Mehrdad:您可以在这里体验一下不同之处:devx.com/dotnet/Article/42590/1954。如需更深入的讨论,请参阅 Anders Hejlsberg 的演讲“C# 的未来”:channel9.msdn.com/Blogs/pdc2008/TL16
    • @Robert @Mehrdad:不是这样。讨厌的不是 COM 互操作(在这方面),它正在开发和注册一个 COM 模块,而新的 C# 4.0 功能对此没有帮助。
    【解决方案5】:

    多年来,我一直在使用 IE 的网络浏览器控件,在此过程中,一个名字一遍又一遍地出现在有用的帖子中:Igor Tandetnik

    如果我正在开发一个扩展程序,我会以 BHO 为目标,然后开始在谷歌上搜索:

    BHO 伊戈尔·坦德尼克

    浏览器帮助对象 Igor Tandetnik

    他的帖子通常很详细,而且他知道自己在说什么。

    您将发现自己在 COM 和 ATL 编程方面表现出色。 有关示例演练,请查看: http://msdn.microsoft.com/en-us/library/ms976373.aspx

    【讨论】:

    • 使用 C# 的最大缺点(这是大多数其他海报所采用的方向)是它将经历各种额外的层,以及代码的变通方法和补丁原生于 C++。
    【解决方案6】:

    我同意 Robert Harvey 的观点,C# 4.0 具有改进的 COM 互操作性。这是一些较旧的 C# 代码,迫切需要重写。

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

    这是通过避免 ATL 并使用 Spartan COM 来简化事情的尝试:

    C++ and COM to get BHOs going

    【讨论】:

      【解决方案7】:

      如果你不想重新发明轮子,你可以试试Add In Express for IE。我已经将产品用于VSTO stuff,它非常好。他们还有一个有用的论坛和快速支持。

      【讨论】:

        【解决方案8】:

        显然已经解决了,但是对于其他用户,我会推荐 SpicIE 框架。我基于它做了我自己的扩展。它仅支持 Internet Explorer 7/8 官方,但我在 Internet Explorer 6-10(从 Windows XP 到 Windows 8 Consumer Preview)上进行了测试,它工作正常。 不幸的是,最新版本中存在一些错误,因此我不得不修复它们并制作了自己的版本: http://archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251

        【讨论】:

          【解决方案9】:

          我热烈地向您推荐 Pavel Zolnikov 2002 年发表的这篇文章!

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

          它基于 Band 对象的使用,使用 .Net 2.0 编译。 提供了源代码,并且可以使用 Visual Studio 2013 很好地打开和编译。 正如您将在帖子 cmets 中看到的那样,它在 IE 11 以及 Windows 7 和 Windows 10 上运行良好。 它在 Windows 7 + SP1 和 IE 11 上非常适合我 享受吧!

          【讨论】:

          • 我们希望答案在 StackOverflow 上是自包含的。这篇文章真正告诉我的是“使用 Band 对象和 .Net 2.0”。您能否在此处包含一些示例代码来说明如何完成?
          【解决方案10】:

          问题是从 2013 年开始,现在是 2020 年,但它可能对未来的访问者有所帮助。

          我尝试实现@Miguel Angelo 的答案,但一开始并没有奏效。

          还有一些你需要定义的设置。

          在 Internet Explorer(我使用的是 IE-11)上转到 Tools--&gt;Internet Options--&gt;Advanced

          另见this SO questionthis example from github

          【讨论】:

            【解决方案11】:

            在 Build Events 选项卡中,将 Post-build events 命令行设置为:(x64) 如下所示

            "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)"
            

            我想要构建事件选项卡,将构建后事件命令行设置为(32 位操作系统)

            "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)"
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-05-22
              • 1970-01-01
              • 2010-11-17
              • 2021-04-10
              • 1970-01-01
              • 2012-06-04
              • 1970-01-01
              • 2020-06-04
              相关资源
              最近更新 更多