[更新]我正在更新此答案,以在带有 Visual Studio 2017社区的* Windows 10 x64中 使用 Internet
Explorer 11 。此答案的先前版本(对于Internet Explorer 8,在Windows 7 x64和Visual Studio
2010中)在此答案的底部。 ***
创建有效的Internet Explorer 11加载项
我使用 的Visual Studio 2017年的社区 , C# , .Net框架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 Studio2017CommunityCommon7ToolsVsDevCmd.bat"cd "%ProgramFiles(x86)%Microsoft Visual Studio2017CommunityCommon7IDEPublicAssemblies"regasm Microsoft.mshtml.dllgacutil /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 }}互操作
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.Unipre)] 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); }}最后是表格,我们将使用它来配置选项。在此表格中,放置a
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
在“构建事件”选项卡中,将 “构建后事件”命令行设置 为:
“%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
如果需要,可以使用64位重装:
%windir% Microsoft.NET framework **64 ** v4.0.30319 RegAsm.exe
此加载项如何工作
我没有更改加载项的行为。。。下面介绍一下IE8部分。
## IE8的先前答案
伙计…这是很多工作!我很好奇如何做到这一点,以至于我自己做了。
首先…信誉不全是我的。这是我在以下网站上发现的内容的汇总:
- CodeProject文章,如何制作BHO;
- 15秒,但它不是15秒,花了大约7个小时;
- Microsoft教程,帮助我添加了命令按钮。
- 这个social.msdn主题帮助我弄清楚该程序集必须在GAC中。
- 此MSDN博客文章包含一个完整的示例
- 许多其他网站,在发现过程中…
当然,我希望我的答案具有您要求的功能:
- DOM遍历以查找某些内容;
- 显示窗口的按钮(以我为例进行设置)
- 保留配置(我将为此使用注册表)
- 最后执行javascript。
我将逐步介绍它,以及如何在 Windows 7 x64中* 使用 Internet Explorer 8 进行 管理
…请注意,我无法在其他配置中进行测试。希望你理解=) *
创建有效的Internet Explorer 8加载项
我使用的是 Visual Studio 2010 , C#4 , .Net framework 4
,因此其中一些步骤可能对您略有不同。
创建了一个类库。我叫我 InternetExplorerExtension 。
将这些引用添加到项目中:
- 互操作
- 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" />
创建文件的方式与更新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;...
互操作
与IE11版本相同。
最后是表格,我们将使用它来配置选项。在此表格中,放置a
TextBox和Ok
Button。将按钮的 DialogResult 设置为
Ok 。该代码与IE11插件相同。
在项目属性中,执行以下操作:
- 用强力钥匙在组件上签名;
- 在“调试”选项卡中,将“ 启动外部程序” 设置为
C:Program Files (x86)Internet Exploreriexplore.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)$(TargetFileName)”
“ 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被视为“导航”,并且需要收听导航事件(也许)。我稍后将尝试解决。
现在,该走了。我很累。随便问问题…也许是因为我要去旅行而无法回答…三天后我会回来,但在此期间我会尽量来这里。



