[UPDATE] Saya memperbarui jawaban ini agar berfungsi dengan Internet Explorer 11 , di Windows 10 x64 dengan Visual Studio 2017 Community . Versi sebelumnya dari jawaban ini (untuk Internet Explorer 8, di Windows 7 x64 dan Visual Studio 2010) ada di bagian bawah jawaban ini.
Membuat Pengaya Internet Explorer 11 Add-on
Saya menggunakan Visual Studio 2017 Community , C # , .Net Framework 4.6.1 , jadi beberapa langkah ini mungkin sedikit berbeda untuk Anda.
Anda perlu membuka Visual Studio sebagai Administrator untuk membangun solusi, sehingga skrip post-build dapat mendaftarkan BHO (perlu akses registri).
Mulailah dengan membuat perpustakaan kelas. Saya menelepon InternetExplorerExtension milik saya .
Tambahkan referensi ini ke proyek:
- Interop.SHDocVw: tab COM / cari
"Microsoft Internet Controls"
- Microsoft.mshtml: Sidang tab / cari
"Microsoft.mshtml"
Catatan: Entah bagaimana MSHTML tidak terdaftar di sistem saya, meskipun saya dapat menemukannya di jendela Tambahkan Referensi. Ini menyebabkan kesalahan saat membangun:
Tidak dapat menemukan unit pembungkus untuk pustaka tipe "MSHTML"
Perbaikan dapat ditemukan di http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html
Atau, Anda dapat menjalankan skrip kumpulan ini:
"%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
Buat file berikut:
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);
}
}
dan akhirnya formulir, yang akan kita gunakan untuk mengonfigurasi opsi. Dalam formulir ini tempat a TextBox
dan sebuah Ok Button
. Atur DialogResult tombol ke Ok . Tempatkan kode ini dalam kode formulir:
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; }
}
}
}
Di properti proyek, lakukan hal berikut:
- Tanda tangani unit dengan kunci yang kuat;
- Di tab Debug, atur Mulai Program Eksternal ke
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- Di tab Debug, atur Argumen Baris Perintah ke
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
Di tab Bangun Acara, setel baris perintah acara Bangun ke:
"% ProgramFiles (x86)% \ Microsoft SDK \ Windows \ v10.0A \ bin \ NETFX 4.6.1 Alat \ gacutil.exe" / f / i "$ (TargetDir) $ (TargetFileName)" "
"% windir% \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" / batalkan pendaftaran "$ (TargetDir) $ (TargetFileName)"
"% windir% \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" "$ (TargetDir) $ (TargetFileName)" "
Perhatian: meskipun komputer saya x64, saya menggunakan jalur non-x64 gacutil.exe
dan berhasil ... yang spesifik untuk x64 adalah di:
C: \ Program Files (x86) \ Microsoft SDKs \ Windows \ v10.0A \ bin \ NETFX 4.6.1 Alat \ x64 \ gacutil.exe
64bit IE Memerlukan BHO 64bit yang dikompilasi dan 64bit. Meskipun saya hanya bisa debug menggunakan IE11 32bit, ekstensi terdaftar 32bit juga bekerja dengan menjalankan 64bit IE11.
Jawaban ini tampaknya memiliki beberapa info tambahan tentang ini: https://stackoverflow.com/a/23004613/195417
Jika perlu, Anda dapat menggunakan regasm 64bit:
% windir% \ Microsoft.NET \ Framework 64 \ v4.0.30319 \ RegAsm.exe
Cara kerja pengaya ini
Saya tidak mengubah perilaku add-on ... lihat bagian IE8 di bawah untuk penjelasan.
## Jawaban Sebelumnya untuk IE8
Sobat ... ini sudah banyak pekerjaan! Saya sangat ingin tahu tentang bagaimana melakukan ini, sehingga saya melakukannya sendiri.
Pertama-tama ... kredit bukan milikku. Ini adalah kompilasi dari apa yang saya temukan, di situs-situs ini:
Dan tentu saja, saya ingin jawaban saya memiliki fitur yang Anda tanyakan:
- DOM traversal untuk menemukan sesuatu;
- sebuah tombol yang menunjukkan jendela (dalam kasus saya untuk mengatur)
- tetap konfigurasi (saya akan menggunakan registri untuk itu)
- dan akhirnya jalankan javascript.
Saya akan menjelaskannya langkah demi langkah, bagaimana saya berhasil melakukannya dengan Internet Explorer 8 , pada Windows 7 x64 ... perhatikan bahwa saya tidak dapat menguji dalam konfigurasi lain. Semoga Anda mengerti =)
Membuat Pengaya Internet Explorer 8 yang Bekerja
Saya menggunakan Visual Studio 2010 , C # 4 , .Net Framework 4 , jadi beberapa langkah ini mungkin sedikit berbeda untuk Anda.
Membuat perpustakaan kelas. Saya menelepon InternetExplorerExtension milik saya .
Tambahkan referensi ini ke proyek:
- Interop.SHDocVw
- Microsoft.mshtml
Catatan: Referensi ini mungkin ada di tempat yang berbeda di setiap komputer.
inilah isi bagian referensi saya di 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" />
Buat file dengan cara yang sama seperti file IE11 yang diperbarui.
IEAddon.cs
Anda dapat menghapus komentar baris berikut dari versi 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
Sama seperti versi IE11.
dan akhirnya formulir, yang akan kita gunakan untuk mengonfigurasi opsi. Dalam formulir ini tempat a TextBox
dan sebuah Ok Button
. Atur DialogResult tombol ke Ok . Kode ini sama untuk addon IE11.
Di properti proyek, lakukan hal berikut:
- Tanda tangani unit dengan kunci yang kuat;
- Di tab Debug, atur Mulai Program Eksternal ke
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- Di tab Debug, atur Argumen Baris Perintah ke
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
Di tab Bangun Acara, setel baris perintah acara Bangun ke:
"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" / batalkan registrasi "$ (TargetDir) $ (TargetFileName)"
"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" "$ (TargetDir) $ (TargetFileName)" "
Perhatian: karena komputer saya adalah x64, ada x64 khusus di dalam jalur gacutil yang dapat dieksekusi di komputer saya yang mungkin berbeda pada Anda.
64bit IE Memerlukan BHO 64bit yang dikompilasi dan 64bit. Gunakan 64bit RegAsm.exe (biasanya hidup di C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ RegAsm.exe)
Cara kerja pengaya ini
Itu melintasi semua pohon DOM, mengganti teks, dikonfigurasi menggunakan tombol, dengan sendirinya dengan latar belakang kuning. Jika Anda mengklik teks yang dikuning, itu memanggil fungsi javascript yang dimasukkan pada halaman secara dinamis. Kata default adalah 'browser', sehingga sangat cocok dengan mereka!
Sunting: setelah mengubah string yang akan disorot, Anda harus mengklik kotak URL dan tekan Enter ... F5 tidak akan berfungsi, saya pikir itu karena F5 dianggap sebagai 'navigasi', dan perlu mendengarkan acara navigasi. (mungkin). Saya akan mencoba memperbaikinya nanti.
Sekarang saatnya untuk pergi. Saya sangat lelah. Jangan ragu untuk bertanya ... mungkin saya tidak akan dapat menjawab karena saya akan melakukan perjalanan ... dalam 3 hari saya kembali, tetapi saya akan mencoba untuk datang ke sini sementara itu.