[CẬP NHẬT] Tôi đang cập nhật câu trả lời này để hoạt động với Internet Explorer 11 , trong Windows 10 x64 với Cộng đồng Visual Studio 2017 . Phiên bản trước của câu trả lời này (dành cho Internet Explorer 8, trong Windows 7 x64 và Visual Studio 2010) nằm ở cuối câu trả lời này.
Tạo một bổ trợ Internet Explorer 11 hoạt động
Tôi đang sử dụng Cộng đồng Visual Studio 2017 , C # , .Net Framework 4.6.1 , vì vậy một số bước này có thể hơi khác với bạn.
Bạn cần mở Visual Studio với tư cách Quản trị viên để xây dựng giải pháp, để tập lệnh hậu xây dựng có thể đăng ký BHO (cần quyền truy cập đăng ký).
Bắt đầu bằng cách tạo một thư viện lớp. Tôi đã gọi cho tôi InternetExplorerExtension .
Thêm các tham chiếu này vào dự án:
- Interop.SHDocVw: tab COM / tìm kiếm
"Microsoft Internet Controls"
- Microsoft.mshtml: tab lắp ráp / tìm kiếm
"Microsoft.mshtml"
Lưu ý: Bằng cách nào đó MSHTML không được đăng ký trong hệ thống của tôi, mặc dù tôi có thể tìm thấy trong cửa sổ Thêm tham chiếu. Điều này gây ra lỗi trong khi xây dựng:
Không thể tìm thấy trình bao bọc cho thư viện kiểu "MSHTML"
Bản sửa lỗi có thể được tìm thấy tại http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assinstall-for.html
Hoặc, bạn có thể chạy tập lệnh bó này:
"%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
Tạo các tệp sau:
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);
}
}
và cuối cùng là một hình thức, mà chúng ta sẽ sử dụng để cấu hình các tùy chọn. Trong hình thức này, đặt một TextBox
và một Ok Button
. Đặt DialogResult của nút thành Ok . Đặt mã này vào mã mẫu:
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; }
}
}
}
Trong các thuộc tính của dự án, làm như sau:
- Ký tên lắp ráp với một phím mạnh;
- Trong tab Gỡ lỗi, đặt Bắt đầu Chương trình Bên ngoài thành
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- Trong tab Gỡ lỗi, đặt Đối số dòng lệnh thành
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
Trong tab Xây dựng sự kiện, đặt dòng lệnh Sự kiện xây dựng sau thành:
"% ProgramFiles (x86)% \ Microsoft SDKs \ Windows \ v10.0A \ bin \ NETFX 4.6.1 Công cụ \ gacutil.exe" / f / i "$ (TargetDir) $ (TargetFileName)"
"% Windir% \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" / hủy đăng ký "$ (TargetDir) $ (TargetFileName)"
"% Windir% \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" "$ (TargetDir) $ (TargetFileName)"
Chú ý: mặc dù máy tính của tôi là x64, tôi đã sử dụng đường dẫn của non-x64 gacutil.exe
và nó hoạt động ... một cái cụ thể cho x64 là:
C: \ Tệp chương trình (x86) \ Microsoft SDKs \ Windows \ v10.0A \ bin \ NETFX 4.6.1 Công cụ \ x64 \ gacutil.exe
Nhu cầu IE 64 bit được biên dịch 64 bit và BHO đăng ký 64 bit. Mặc dù tôi chỉ có thể gỡ lỗi bằng IE11 32 bit, nhưng tiện ích mở rộng đã đăng ký 32 bit cũng hoạt động bằng cách chạy IE11 64 bit.
Câu trả lời này dường như có một số thông tin bổ sung về điều này: https://stackoverflow.com/a/23004613/195417
Nếu bạn cần, bạn có thể sử dụng hồi quy 64 bit:
% Windir% \ Microsoft.NET \ Framework 64 \ v4.0.30319 \ RegAsm.exe
Cách bổ trợ này hoạt động
Tôi đã không thay đổi hành vi của tiện ích bổ sung ... hãy xem phần IE8 dưới đây để mô tả.
## Câu trả lời trước cho IE8
Man ... đây là một công việc rất nhiều! Tôi đã rất tò mò về cách làm điều này, mà tôi đã tự làm nó.
Trước hết ... tín dụng không phải là tất cả của tôi. Đây là một bản tổng hợp những gì tôi tìm thấy, trên các trang web này:
Và tất nhiên, tôi muốn câu trả lời của tôi có các tính năng bạn đã hỏi:
- DOM traversal để tìm một cái gì đó;
- một nút hiển thị một cửa sổ (trong trường hợp của tôi để thiết lập)
- duy trì cấu hình (tôi sẽ sử dụng registry cho điều đó)
- và cuối cùng thực thi javascript.
Tôi sẽ mô tả từng bước một, cách tôi quản lý để làm việc với Internet Explorer 8 , trong Windows 7 x64 ... lưu ý rằng tôi không thể kiểm tra các cấu hình khác. Mong bạn hiểu =)
Tạo một bổ trợ Internet Explorer 8 hoạt động
Tôi đang sử dụng Visual Studio 2010 , C # 4 , .Net Framework 4 , vì vậy một số bước này có thể hơi khác với bạn.
Tạo một thư viện lớp. Tôi gọi tôi là InternetExplorerExtension .
Thêm các tham chiếu này vào dự án:
- Interop.SHDocVw
- Microsoft.mshtml
Lưu ý: Các tài liệu tham khảo này có thể ở những nơi khác nhau trong mỗi máy tính.
đây là phần tham chiếu của tôi trong csproj chứa:
<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" />
Tạo các tệp giống như các tệp IE11 được cập nhật.
IEAddon.cs
Bạn có thể bỏ ghi chú các dòng sau từ phiên bản 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
Tương tự như phiên bản IE11.
và cuối cùng là một hình thức, mà chúng ta sẽ sử dụng để cấu hình các tùy chọn. Trong hình thức này, đặt một TextBox
và một Ok Button
. Đặt DialogResult của nút thành Ok . Mã này giống với addon IE11.
Trong các thuộc tính của dự án, làm như sau:
- Ký tên lắp ráp với một phím mạnh;
- Trong tab Gỡ lỗi, đặt Bắt đầu Chương trình bên ngoài thành
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- Trong tab Gỡ lỗi, đặt Đối số dòng lệnh thành
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
Trong tab Xây dựng sự kiện, đặt dòng lệnh Sự kiện xây dựng sau thành:
"C: \ Tệp chương trình (x86) \ Microsoft SDKs \ Windows \ v7.0A \ Bin \ NETFX 4.0 Công cụ \ x64 \ gacutil.exe" / f / i "$ (TargetDir) $ (TargetFileName)"
"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" / hủy đăng ký "$ (TargetDir) $ (TargetFileName)"
"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" "$ (TargetDir) $ (TargetFileName)"
Chú ý: vì máy tính của tôi là x64, có một x64 cụ thể bên trong đường dẫn thực thi gacutil trên máy của tôi có thể khác với máy của bạn.
IE 64 bitNhu cầu 64 bit được biên dịch 64 bit và BHO đăng ký 64 bit. Sử dụng RegAsm.exe 64 bit (thường sống trong C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ RegAsm.exe)
Cách bổ trợ này hoạt động
Nó đi qua tất cả cây DOM, thay thế văn bản, được định cấu hình bằng nút, bằng nền màu vàng. Nếu bạn nhấp vào các văn bản màu vàng, nó sẽ gọi một hàm javascript được chèn trên trang một cách linh hoạt. Từ mặc định là 'trình duyệt', vì vậy nó phù hợp với rất nhiều từ đó!
EDIT: sau khi thay đổi chuỗi được tô sáng, bạn phải nhấp vào hộp URL và nhấn Enter ... F5 sẽ không hoạt động, tôi nghĩ rằng đó là vì F5 được coi là 'điều hướng' và nó sẽ yêu cầu lắng nghe để điều hướng sự kiện (có lẽ). Tôi sẽ cố gắng khắc phục điều đó sau.
Bây giờ, đã đến lúc phải đi. Tôi rất mệt. Vui lòng đặt câu hỏi ... có thể tôi sẽ không thể trả lời vì tôi đang đi du lịch ... trong 3 ngày tôi sẽ quay lại, nhưng tôi sẽ cố gắng đến đây trong thời gian này.