[UPDATE] Ich aktualisiere diese Antwort, um mit Internet Explorer 11 in Windows 10 x64 mit Visual Studio 2017 Community zu arbeiten . Die vorherige Version dieser Antwort (für Internet Explorer 8 in Windows 7 x64 und Visual Studio 2010) befindet sich am Ende dieser Antwort.
Erstellen eines funktionierenden Internet Explorer 11-Add-ons
Ich verwende Visual Studio 2017 Community , C # , .Net Framework 4.6.1 , daher können einige dieser Schritte für Sie etwas anders sein.
Sie müssen Visual Studio als Administrator öffnen , um die Lösung zu erstellen, damit das Post-Build-Skript das BHO registrieren kann (Registrierungszugriff erforderlich).
Erstellen Sie zunächst eine Klassenbibliothek. Ich habe meine InternetExplorerExtension angerufen .
Fügen Sie dem Projekt diese Verweise hinzu:
- Interop.SHDocVw: Registerkarte COM / Suche nach
"Microsoft Internet Controls"
- Microsoft.mshtml: Registerkarte / Suche nach Baugruppen
"Microsoft.mshtml"
Hinweis: Irgendwie wurde MSHTML nicht in meinem System registriert, obwohl ich es im Fenster Referenz hinzufügen finden konnte. Dies verursachte einen Fehler beim Erstellen:
Wrapper-Assembly für Typbibliothek "MSHTML" kann nicht gefunden werden
Das Update finden Sie unter http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html
. Sie können auch dieses Batch-Skript ausführen:
"%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
Erstellen Sie die folgenden Dateien:
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);
}
}
und schließlich ein Formular, mit dem wir die Optionen konfigurieren. In dieser Form platzieren Sie ein TextBox
und ein Ok Button
. Stellen Sie die Dialogresult der Schaltfläche Ok . Fügen Sie diesen Code in den Formularcode ein:
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; }
}
}
}
Gehen Sie in den Projekteigenschaften wie folgt vor:
- Unterschreiben Sie die Versammlung mit einem starken Schlüssel.
- Setzen Sie auf der Registerkarte Debuggen auf Externes Programm starten auf
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- Setzen Sie auf der Registerkarte Debuggen Befehlszeilenargumente auf
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
Setzen Sie auf der Registerkarte Build -Ereignisse die Befehlszeile Post-Build-Ereignisse auf:
"% 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" / unregister "$ (TargetDir) $ (TargetFileName)"
"% windir% \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" "$ (TargetDir) $ (TargetFileName)"
Achtung: Obwohl mein Computer x64 ist, habe ich den Pfad des Nicht-x64 verwendet gacutil.exe
und es hat funktioniert ... der für x64 spezifische ist:
C: \ Programme (x86) \ Microsoft SDKs \ Windows \ v10.0A \ bin \ NETFX 4.6.1 Tools \ x64 \ gacutil.exe
64- Bit- IE Benötigt 64-Bit-kompiliertes und 64-Bit-registriertes BHO. Obwohl ich nur mit 32-Bit-IE11 debuggen konnte, funktionierte die registrierte 32-Bit-Erweiterung auch mit 64-Bit-IE11.
Diese Antwort scheint einige zusätzliche Informationen zu enthalten: https://stackoverflow.com/a/23004613/195417
Wenn nötig, können Sie das 64-Bit-Regime verwenden:
% windir% \ Microsoft.NET \ Framework 64 \ v4.0.30319 \ RegAsm.exe
Wie dieses Add-On funktioniert
Ich habe das Verhalten des Add-Ons nicht geändert. Eine Beschreibung finden Sie im Abschnitt IE8 unten.
## Vorherige Antwort für IE8
Mann ... das war viel Arbeit! Ich war so neugierig, wie ich das machen sollte, dass ich es selbst gemacht habe.
Zuallererst ... Kredit ist nicht alles von mir. Dies ist eine Zusammenstellung dessen, was ich auf diesen Websites gefunden habe:
Und natürlich wollte ich, dass meine Antwort die Funktionen enthält, die Sie gefragt haben:
- DOM-Durchquerung, um etwas zu finden;
- eine Schaltfläche, die ein Fenster anzeigt (in meinem Fall zum Einrichten)
- Behalte die Konfiguration bei (ich werde dafür die Registrierung verwenden)
- und schließlich Javascript ausführen.
Ich werde es Schritt für Schritt beschreiben, wie ich es mit Internet Explorer 8 in Windows 7 x64 geschafft habe ... Beachten Sie, dass ich in anderen Konfigurationen nicht testen konnte. Hoffe du verstehst =)
Erstellen eines funktionierenden Internet Explorer 8-Add-ons
Ich verwende Visual Studio 2010 , C # 4 , .Net Framework 4 , daher können einige dieser Schritte für Sie etwas anders sein.
Erstellt eine Klassenbibliothek. Ich habe meine InternetExplorerExtension angerufen .
Fügen Sie dem Projekt diese Verweise hinzu:
- Interop.SHDocVw
- Microsoft.mshtml
Hinweis: Diese Referenzen befinden sich möglicherweise an verschiedenen Stellen in jedem Computer.
Dies ist, was mein Referenzabschnitt in csproj enthält:
<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" />
Erstellen Sie die Dateien auf die gleiche Weise wie die aktualisierten IE11-Dateien.
IEAddon.cs
Sie können die folgenden Zeilen aus der IE11-Version auskommentieren:
...
// @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
Gleich wie IE11-Version.
und schließlich ein Formular, mit dem wir die Optionen konfigurieren. In dieser Form platzieren Sie ein TextBox
und ein Ok Button
. Stellen Sie die Dialogresult der Schaltfläche Ok . Der Code ist der gleiche für das IE11-Addon.
Gehen Sie in den Projekteigenschaften wie folgt vor:
- Unterschreiben Sie die Versammlung mit einem starken Schlüssel.
- Setzen Sie auf der Registerkarte Debuggen auf Externes Programm starten auf
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- Setzen Sie auf der Registerkarte Debuggen Befehlszeilenargumente auf
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
Setzen Sie auf der Registerkarte Build -Ereignisse die Befehlszeile Post-Build-Ereignisse auf:
"C: \ Programme (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" / unregister "$ (TargetDir) $ (TargetFileName)"
"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ RegAsm.exe" "$ (TargetDir) $ (TargetFileName)"
Achtung: Da mein Computer x64 ist, befindet sich im Pfad der ausführbaren Datei von gacutil auf meinem Computer ein bestimmtes x64, das auf Ihrem Computer möglicherweise anders ist.
64- Bit- IE Benötigt 64-Bit-kompiliertes und 64-Bit-registriertes BHO. Verwenden Sie 64-Bit-RegAsm.exe (normalerweise in C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ RegAsm.exe).
Wie dieses Add-On funktioniert
Es durchläuft den gesamten DOM-Baum und ersetzt den mit der Schaltfläche konfigurierten Text durch einen gelben Hintergrund. Wenn Sie auf die vergilbten Texte klicken, wird eine Javascript-Funktion aufgerufen, die dynamisch auf der Seite eingefügt wurde. Das Standardwort ist "Browser", so dass es mit vielen von ihnen übereinstimmt!
BEARBEITEN: Nachdem Sie die hervorzuhebende Zeichenfolge geändert haben, müssen Sie auf das URL-Feld klicken und die Eingabetaste drücken. F5 funktioniert nicht. Ich denke, dies liegt daran, dass F5 als 'Navigation' betrachtet wird und das Navigationsereignis abgehört werden muss (vielleicht). Ich werde versuchen, das später zu beheben.
Jetzt ist es Zeit zu gehen. Ich bin sehr müde. Fühlen Sie sich frei, Fragen zu stellen ... vielleicht kann ich nicht antworten, da ich auf eine Reise gehe ... in 3 Tagen bin ich zurück, aber ich werde versuchen, in der Zwischenzeit hierher zu kommen.