Does anyone here have experience with/in developing IE extensions that can share their knowledge? This would include code samples, or links to good ones, or documentation on the process, or anything.
这里有人有开发IE扩展的经验吗?这将包括代码示例、指向好的示例的链接、过程的文档或任何东西。
I really want to do this, but I'm hitting a giant wall with lousy documentation, lousy code/example code/lack thereof. Any help/resources you could offer would be greatly appreciated.
我确实想这样做,但是我遇到了一个巨大的墙壁,上面有糟糕的文档、糟糕的代码/示例代码/缺乏这些。如果您能提供任何帮助/资源,我们将不胜感激。
Specifically, I would like to start with how to get access to/manipulate the DOM from within a IE extension.
具体地说,我想从如何从IE扩展中访问/操作DOM开始。
EDIT, even more details:
编辑,甚至更多的细节:
Ideally, I would like to plant a toolbar button that, when clicked, popped a menu up that contains links to external sites. I would also like to access the DOM and plant JavaScript on the page depending on some conditions.
理想情况下,我想要放置一个工具栏按钮,当单击时,弹出一个包含到外部站点的链接的菜单。我还希望访问DOM并根据某些条件在页面上放置JavaScript。
What is the best way to persist information in an IE extension? In Firefox/Chrome/Most modern browsers, you use window.localStorage
, but obviously with IE8/IE7, that's not an option. Maybe a SQLite DB or such? It is okay to assume that .NET 4.0 will be installed on a user's computer?
在IE扩展中保存信息的最佳方式是什么?在Firefox/Chrome/大多数现代浏览器中,你使用窗口。localStorage,但是显然对于IE8/IE7来说,这不是一个选项。或者一个SQLite DB ?假设。net 4.0将被安装在用户的计算机上是可以的吗?
I don't want to use Spice IE as I want to build one that is compatible with IE9 as well. I've added the C++ tag to this question as well, because if it's better to build one in C++, I can do that.
我不想使用Spice IE,因为我想要构建一个与IE9兼容的版本。我还为这个问题添加了c++标记,因为如果用c++构建一个更好,我可以这么做。
10 个解决方案
#1
214
Man... this has been a lot of work! I was so curious about how to do this, that I did it myself.
男人。这是一项艰巨的工作!我很好奇该怎么做,所以我自己做了。
First of all... credit is not all mine. This is a compilation of what I found, on these sites:
首先……信用不是我的全部。这是我在这些网站上发现的,
- CodeProject article, how to make a BHO;
- 代码项目文章,如何制作BHO;
- 15seconds, but it was not 15 seconds, it took about 7 hours;
- 15秒,但不是15秒,而是7小时;
- Microsoft tutorial, helped me adding the command button.
- 微软教程,帮助我添加命令按钮。
- And this social.msdn topic, that helped me figure out that the assembly must be in the GAC.
- 这社会。msdn的主题,这帮助我理解了程序集必须在GAC中。
- This recent MSDN blog post contains a fully-working example
- 最近的MSDN博客文章包含了一个完整的示例
- many other sites, in the discovery process...
- 许多其他的网站,在发现的过程中……
And of course, I wanted my answer to have the features you asked:
当然,我想让我的回答有你问的特征:
- DOM traversal to find something;
- 遍历DOM找到某个东西;
- a button that shows a window (in my case to setup)
- 显示窗口的按钮(以我为例)
- persist the configuration (I will use regitry for that)
- 持久化配置(我将使用regitry)
- and finally execute javascript.
- 最后执行javascript。
I will describe it step by step, how I managed to do it working with Internet Explorer 8, in Windows 7 x64... note that I could not test in other configurations. Hope you understand =)
我将一步一步地描述它,我如何在Windows 7 x64中使用Internet Explorer 8实现它……注意,我不能在其他配置中进行测试。希望你理解=)
Creating a Working Internet Explorer 8 Addon
I am using Visual Studio 2010, C# 4, .Net Framework 4, so some of these steps might be slightly different for you.
我使用的是Visual Studio 2010, c# 4,。net Framework 4,所以这些步骤对您来说可能有些不同。
Created a class library. I called mine InternetExplorerExtension.
创建了一个类库。我叫InternetExplorerExtension。
Add these references to the project:
将这些引用添加到项目中:
- Interop.SHDocVw
- Interop.SHDocVw
- Microsoft.mshtml
- Microsoft.mshtml
Note: These references may be in different places in each computer.
注意:这些引用可能位于每台计算机的不同位置。
this is what my references section in csproj contains:
这是我在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" />
Create the following files:
创建以下文件:
IEAddon.cs
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 will prevent this method being executed more than once.
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
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);
}
}
and finally a form, that we will use to configure the options. In this form place a TextBox
and an Ok Button
. Set the DialogResult of the button to Ok. Place this code in the form code:
最后是一个表单,我们将使用它来配置选项。在这个表单中放置一个文本框和一个Ok按钮。将按钮的对话框设置为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; }
}
}
}
In the project properties, do the following:
在项目属性中,执行以下操作:
- Sign the assembly with a strong-key;
- 用万能钥匙在总成上签字;
- In the Debug tab, set Start External Program to
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- 在Debug选项卡,设置启动外部程序C:\Program Files (x86)\Internet Explorer \ iexplore.exe
- In the Debug tab, set Command Line Arguments to
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
- 在Debug选项卡中,将命令行参数设置为http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
-
In the Build Events tab, set Post-build events command line to:
在Build Events选项卡中,将构建后事件命令行设置为:
"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" /unregister "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
Attention: as my computer is x64, there is a specific x64 inside the path of gacutil executable on my machine that may be different on yours.
注意:由于我的计算机是x64,所以在我的计算机上gacutil可执行文件的路径中有一个特定的x64,您的计算机上可能有不同。
64bit IE Needs 64bit-compiled and 64bit-registered BHO. Use 64bit RegAsm.exe (usually lives in C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe)
64位IE需要64位编译和64位注册BHO。使用64位RegAsm。exe(通常生活在C:\Windows\ Microsoft.NET \ Framework64 \ v4.0.30319 \ RegAsm.exe)
How this addon works
它是如何工作的
It traverses all DOM tree, replacing the text, configured using the button, by itself with a yellow background. If you click on the yellowed texts, it calls a javascript function that was inserted on the page dynamically. The default word is 'browser', so that it matches a lot of them! EDIT: after changing the string to be highlighted, you must click the URL box and press Enter... F5 will not work, I think that it is because F5 is considered as 'navigation', and it would require to listen to navigate event (maybe). I'll try to fix that later.
它遍历所有DOM树,替换使用按钮配置的文本,单独使用黄色背景。如果单击泛黄的文本,它将调用动态插入页面的javascript函数。默认的词是“浏览器”,所以它匹配很多!编辑:更改要突出显示的字符串后,必须单击URL框并按Enter…F5不起作用,我认为是因为F5被认为是“导航”,需要听导航事件(也许)。我稍后再解决这个问题。
Now, it is time to go. I am very tired. Feel free to ask questions... may be I will not be abled to answer since I am going on a trip... in 3 days I'm back, but I'll try to come here in the meantime.
现在,该走了。我很累了。请随意提问……因为我要去旅行,所以我不会轻易回答……过三天我就回来了,但同时我会试着来这里。
#2
13
Another cool approach would be to check out:
另一个很酷的方法是:
http://www.crossrider.org
It's a framework based on JS with jquery which lets you develop browsers extensions for IE, FF and Chrome using a single common JS code. Basically the framework does all the nasty work and you're left with writing your applications code.
它是一个基于JS和jquery的框架,允许您使用一个通用的JS代码为IE、FF和Chrome开发浏览器扩展。基本上框架完成了所有令人讨厌的工作,剩下的就是编写应用程序代码了。
#3
11
The state for IE extensions is actually pretty sad. You have the old model of IE5 Browser Helper Object (yeah, those infamous BHOs that everyone liked to block back in the day), toolbars and the new accelerators for IE. Even then, compatibility will break sometimes. I used to maintain an extension for IE6 that broke with IE7, so there are some things that have changed. For the most part, as far as I know (I haven't touch BHOs in years) you still need to code them using Active Template Libraries (kind of like an STL for Microsoft's COM) and well as such is only for C++. You could do COM Interop with C# and get away with doing it in C# but its probably going to be too hard for what it is worth. Anyway, if you are interested in coding your own extension for IE (which is plausible if you want to have your extensions available in all major browsers) here are the official Microsoft Resources.
IE扩展的状态实际上相当令人沮丧。你有旧的IE5浏览器助手对象的模型(是的,那些臭名昭著的BHOs,当时每个人都喜欢屏蔽),工具栏和IE的新加速器。即便如此,兼容性有时也会崩溃。我曾经为IE6维护过一个扩展,它在IE7中被破坏了,所以有些东西已经改变了。就我所知,大多数情况下(我已经很多年没有接触过BHOs了),您仍然需要使用活动模板库(有点像微软的COM的STL)对它们进行编码,而且只针对c++。你可以用c#进行COM互操作,然后在c#中进行操作,但这可能对它的价值来说太难了。无论如何,如果您对为IE编写自己的扩展感兴趣(如果您希望在所有主要浏览器中都可以使用扩展,这是合理的),这里是Microsoft官方资源。
http://msdn.microsoft.com/en-us/library/aa753587(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/aa753587(v = vs.85). aspx
And for the accelerators that are new in IE8 you could check this one.
对于IE8中的加速器你可以检查一下这个。
http://msdn.microsoft.com/en-us/library/cc289775(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/cc289775(v = vs.85). aspx
I agree the documentation is terrible, and the APIs are quite outdated. Still I hope this helps.
我同意文档很糟糕,而且api已经过时了。我仍然希望这能有所帮助。
EDIT: I guess I can throw one last source of information here. I was looking through my notes of back when I was working on BHOs. And this is the article that got me started with them. It is kind of old, but has a good explanation of the ATL interfaces that you will be using when working with IE BHOs (IObjectWithSite for example). I think it is pretty well explained and helped me a lot back then. http://msdn.microsoft.com/en-us/library/bb250436.aspx I also checked the example that GregC posted. It does work with at least IE8, and it is compatible with VS 2010, so if you want to do C# you can get started there and take a look at Jon Skeet's Book. (C# in Depth 2nd edition) Chapter 13 has a good deal of information about the new features in C# 4 that you can use to make the interaction with COM nicer. (I would still recommend you doing your addin in C++)
编辑:我想我可以在这里提供最后一个信息来源。当我在研究BHOs时,我正在翻看我的背记。这篇文章让我从他们开始。它有点旧了,但是对使用IE BHOs(例如IObjectWithSite)时使用的ATL接口有很好的解释。我认为这很好地解释了当时的情况,也给了我很多帮助。我还检查了GregC发布的示例。它至少适用于IE8,并且与VS 2010兼容,所以如果你想做c#,你可以从那里开始,看看Jon Skeet的书。(c#深度第二版)第13章有很多关于c# 4的新特性的信息,您可以使用这些信息来更好地与COM进行交互。(我还是建议你用c++写addin)
#4
7
Developing C# BHOs is a pain-in-the-arse. It involves a lot of icky COM code and p/invoke calls.
开发c# BHOs是件麻烦事。它包含大量的COM代码和p/invoke调用。
I have a mostly finished C# BHO here, which you are free to use the source for whatever you want. I say "mostly", because I never did figure out how to save appdata under IE Protected Mode.
我在这里有一个基本完成的c# BHO,你可以*地使用源代码来做任何你想做的事情。我说“大部分”,是因为我从来没想过如何在IE保护模式下保存appdata。
#5
5
I've been working with IE's webbrowser control for years now, and over the course of them, one name comes up over and over again with helpful postings: Igor Tandetnik
多年来,我一直在使用IE的网络浏览器控件,在此过程中,有一个名字不断地出现,并提供了有用的信息:Igor Tandetnik
If I were developing an extension, I would target a BHO, and start googling for:
如果我正在开发扩展,我会以一个BHO为目标,并开始在谷歌上搜索:
BHO Igor Tandetnik
BHO Igor Tandetnik
OR
或
Browser Helper Object Igor Tandetnik
浏览器助手对象Igor Tandetnik
His postings are often very detailed, and he knows what he is talking about.
他的帖子往往非常详细,他知道自己在说什么。
You're going to find yourself up to your ears in COM and ATL programming. For a sample walkthrough, check out: http://msdn.microsoft.com/en-us/library/ms976373.aspx
在COM和ATL程序设计中,你会发现自己的耳朵都快到耳朵了。有关示例演练,请参阅:http://msdn.microsoft.com/en-us/library/ms976373.aspx
#6
3
I agree with Robert Harvey, C# 4.0 features improved COM interop. Here's a bit of older C# code, in desperate need of a re-write.
我同意Robert Harvey的观点,c# 4.0特性改进了COM interop。这里有一些旧的c#代码,急需重写。
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
This is an attempt to simplify things by avoiding ATL and going with Spartan COM:
这是一种通过避免ATL和使用Spartan COM来简化事情的尝试:
c++和COM让BHOs运行
#7
3
If you are not trying to reinvent the wheel, you might try Add In Express for IE . I have used the product for the VSTO stuff, and its pretty good. Also they have a helpful forum and quick support.
如果您不尝试重新创建*,您可以尝试为IE添加Express。我用过VSTO类的产品,它相当不错。他们也有一个有用的论坛和快速的支持。
#8
3
It is obviously solved, but for the other users, I would recommend SpicIE framework. I have made my own extension based on it. It only supports Internet Explorer 7/8 officialy, but I tested that on Internet Explorer 6-10 (from Windows XP to Windows 8 Consumer Preview) and it works fine. Unfortunately there were some bugs in the latest release, so I had to fix them and made my own release: http://archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251
显然已经解决了,但是对于其他用户,我推荐SpicIE框架。我已经基于它做了我自己的扩展。它只支持ie7 /8的官方版本,但我在ie6 -10(从Windows XP到Windows 8消费者预览版)上测试过,运行良好。不幸的是,最近的版本中出现了一些错误,所以我不得不修复它们,并制作了自己的版本:http://archive.msdn.microsoft.com/spicie/thread/view.aspx?
#9
0
I warmly suggest you this post of Pavel Zolnikov published in 2002!
我热情地建议您在2002年发表这篇帕维尔·佐尔尼科夫的文章!
http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and
http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and
It is based on the use of Band objects and is compiled using .Net 2.0. Source code is provided and opens and compiles well with Visual Studio 2013. As you will read on the post comments it works perfectly well for IE 11 and on Windows 7 and Windows 10. It worked perfectly well for me on Windows 7 + SP1 and IE 11 Enjoy!
它基于带对象的使用,使用。net 2.0编译。源代码是提供,打开和编译与Visual Studio 2013。正如你在文章评论中看到的那样,它在IE 11、Windows 7和Windows 10上运行得非常好。它在Windows 7 + SP1和IE 11上运行得非常好!
#10
-2
In the Build Events tab, set Post-build events command line to: (x64) is listed below
在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)"
I want the Build Events tab , set Post-build events command line to (32 bit operating system)
我想要Build Events选项卡,将构建后事件命令行设置为(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)"
#1
214
Man... this has been a lot of work! I was so curious about how to do this, that I did it myself.
男人。这是一项艰巨的工作!我很好奇该怎么做,所以我自己做了。
First of all... credit is not all mine. This is a compilation of what I found, on these sites:
首先……信用不是我的全部。这是我在这些网站上发现的,
- CodeProject article, how to make a BHO;
- 代码项目文章,如何制作BHO;
- 15seconds, but it was not 15 seconds, it took about 7 hours;
- 15秒,但不是15秒,而是7小时;
- Microsoft tutorial, helped me adding the command button.
- 微软教程,帮助我添加命令按钮。
- And this social.msdn topic, that helped me figure out that the assembly must be in the GAC.
- 这社会。msdn的主题,这帮助我理解了程序集必须在GAC中。
- This recent MSDN blog post contains a fully-working example
- 最近的MSDN博客文章包含了一个完整的示例
- many other sites, in the discovery process...
- 许多其他的网站,在发现的过程中……
And of course, I wanted my answer to have the features you asked:
当然,我想让我的回答有你问的特征:
- DOM traversal to find something;
- 遍历DOM找到某个东西;
- a button that shows a window (in my case to setup)
- 显示窗口的按钮(以我为例)
- persist the configuration (I will use regitry for that)
- 持久化配置(我将使用regitry)
- and finally execute javascript.
- 最后执行javascript。
I will describe it step by step, how I managed to do it working with Internet Explorer 8, in Windows 7 x64... note that I could not test in other configurations. Hope you understand =)
我将一步一步地描述它,我如何在Windows 7 x64中使用Internet Explorer 8实现它……注意,我不能在其他配置中进行测试。希望你理解=)
Creating a Working Internet Explorer 8 Addon
I am using Visual Studio 2010, C# 4, .Net Framework 4, so some of these steps might be slightly different for you.
我使用的是Visual Studio 2010, c# 4,。net Framework 4,所以这些步骤对您来说可能有些不同。
Created a class library. I called mine InternetExplorerExtension.
创建了一个类库。我叫InternetExplorerExtension。
Add these references to the project:
将这些引用添加到项目中:
- Interop.SHDocVw
- Interop.SHDocVw
- Microsoft.mshtml
- Microsoft.mshtml
Note: These references may be in different places in each computer.
注意:这些引用可能位于每台计算机的不同位置。
this is what my references section in csproj contains:
这是我在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" />
Create the following files:
创建以下文件:
IEAddon.cs
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 will prevent this method being executed more than once.
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
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);
}
}
and finally a form, that we will use to configure the options. In this form place a TextBox
and an Ok Button
. Set the DialogResult of the button to Ok. Place this code in the form code:
最后是一个表单,我们将使用它来配置选项。在这个表单中放置一个文本框和一个Ok按钮。将按钮的对话框设置为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; }
}
}
}
In the project properties, do the following:
在项目属性中,执行以下操作:
- Sign the assembly with a strong-key;
- 用万能钥匙在总成上签字;
- In the Debug tab, set Start External Program to
C:\Program Files (x86)\Internet Explorer\iexplore.exe
- 在Debug选项卡,设置启动外部程序C:\Program Files (x86)\Internet Explorer \ iexplore.exe
- In the Debug tab, set Command Line Arguments to
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
- 在Debug选项卡中,将命令行参数设置为http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
-
In the Build Events tab, set Post-build events command line to:
在Build Events选项卡中,将构建后事件命令行设置为:
"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" /unregister "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
Attention: as my computer is x64, there is a specific x64 inside the path of gacutil executable on my machine that may be different on yours.
注意:由于我的计算机是x64,所以在我的计算机上gacutil可执行文件的路径中有一个特定的x64,您的计算机上可能有不同。
64bit IE Needs 64bit-compiled and 64bit-registered BHO. Use 64bit RegAsm.exe (usually lives in C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe)
64位IE需要64位编译和64位注册BHO。使用64位RegAsm。exe(通常生活在C:\Windows\ Microsoft.NET \ Framework64 \ v4.0.30319 \ RegAsm.exe)
How this addon works
它是如何工作的
It traverses all DOM tree, replacing the text, configured using the button, by itself with a yellow background. If you click on the yellowed texts, it calls a javascript function that was inserted on the page dynamically. The default word is 'browser', so that it matches a lot of them! EDIT: after changing the string to be highlighted, you must click the URL box and press Enter... F5 will not work, I think that it is because F5 is considered as 'navigation', and it would require to listen to navigate event (maybe). I'll try to fix that later.
它遍历所有DOM树,替换使用按钮配置的文本,单独使用黄色背景。如果单击泛黄的文本,它将调用动态插入页面的javascript函数。默认的词是“浏览器”,所以它匹配很多!编辑:更改要突出显示的字符串后,必须单击URL框并按Enter…F5不起作用,我认为是因为F5被认为是“导航”,需要听导航事件(也许)。我稍后再解决这个问题。
Now, it is time to go. I am very tired. Feel free to ask questions... may be I will not be abled to answer since I am going on a trip... in 3 days I'm back, but I'll try to come here in the meantime.
现在,该走了。我很累了。请随意提问……因为我要去旅行,所以我不会轻易回答……过三天我就回来了,但同时我会试着来这里。
#2
13
Another cool approach would be to check out:
另一个很酷的方法是:
http://www.crossrider.org
It's a framework based on JS with jquery which lets you develop browsers extensions for IE, FF and Chrome using a single common JS code. Basically the framework does all the nasty work and you're left with writing your applications code.
它是一个基于JS和jquery的框架,允许您使用一个通用的JS代码为IE、FF和Chrome开发浏览器扩展。基本上框架完成了所有令人讨厌的工作,剩下的就是编写应用程序代码了。
#3
11
The state for IE extensions is actually pretty sad. You have the old model of IE5 Browser Helper Object (yeah, those infamous BHOs that everyone liked to block back in the day), toolbars and the new accelerators for IE. Even then, compatibility will break sometimes. I used to maintain an extension for IE6 that broke with IE7, so there are some things that have changed. For the most part, as far as I know (I haven't touch BHOs in years) you still need to code them using Active Template Libraries (kind of like an STL for Microsoft's COM) and well as such is only for C++. You could do COM Interop with C# and get away with doing it in C# but its probably going to be too hard for what it is worth. Anyway, if you are interested in coding your own extension for IE (which is plausible if you want to have your extensions available in all major browsers) here are the official Microsoft Resources.
IE扩展的状态实际上相当令人沮丧。你有旧的IE5浏览器助手对象的模型(是的,那些臭名昭著的BHOs,当时每个人都喜欢屏蔽),工具栏和IE的新加速器。即便如此,兼容性有时也会崩溃。我曾经为IE6维护过一个扩展,它在IE7中被破坏了,所以有些东西已经改变了。就我所知,大多数情况下(我已经很多年没有接触过BHOs了),您仍然需要使用活动模板库(有点像微软的COM的STL)对它们进行编码,而且只针对c++。你可以用c#进行COM互操作,然后在c#中进行操作,但这可能对它的价值来说太难了。无论如何,如果您对为IE编写自己的扩展感兴趣(如果您希望在所有主要浏览器中都可以使用扩展,这是合理的),这里是Microsoft官方资源。
http://msdn.microsoft.com/en-us/library/aa753587(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/aa753587(v = vs.85). aspx
And for the accelerators that are new in IE8 you could check this one.
对于IE8中的加速器你可以检查一下这个。
http://msdn.microsoft.com/en-us/library/cc289775(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/cc289775(v = vs.85). aspx
I agree the documentation is terrible, and the APIs are quite outdated. Still I hope this helps.
我同意文档很糟糕,而且api已经过时了。我仍然希望这能有所帮助。
EDIT: I guess I can throw one last source of information here. I was looking through my notes of back when I was working on BHOs. And this is the article that got me started with them. It is kind of old, but has a good explanation of the ATL interfaces that you will be using when working with IE BHOs (IObjectWithSite for example). I think it is pretty well explained and helped me a lot back then. http://msdn.microsoft.com/en-us/library/bb250436.aspx I also checked the example that GregC posted. It does work with at least IE8, and it is compatible with VS 2010, so if you want to do C# you can get started there and take a look at Jon Skeet's Book. (C# in Depth 2nd edition) Chapter 13 has a good deal of information about the new features in C# 4 that you can use to make the interaction with COM nicer. (I would still recommend you doing your addin in C++)
编辑:我想我可以在这里提供最后一个信息来源。当我在研究BHOs时,我正在翻看我的背记。这篇文章让我从他们开始。它有点旧了,但是对使用IE BHOs(例如IObjectWithSite)时使用的ATL接口有很好的解释。我认为这很好地解释了当时的情况,也给了我很多帮助。我还检查了GregC发布的示例。它至少适用于IE8,并且与VS 2010兼容,所以如果你想做c#,你可以从那里开始,看看Jon Skeet的书。(c#深度第二版)第13章有很多关于c# 4的新特性的信息,您可以使用这些信息来更好地与COM进行交互。(我还是建议你用c++写addin)
#4
7
Developing C# BHOs is a pain-in-the-arse. It involves a lot of icky COM code and p/invoke calls.
开发c# BHOs是件麻烦事。它包含大量的COM代码和p/invoke调用。
I have a mostly finished C# BHO here, which you are free to use the source for whatever you want. I say "mostly", because I never did figure out how to save appdata under IE Protected Mode.
我在这里有一个基本完成的c# BHO,你可以*地使用源代码来做任何你想做的事情。我说“大部分”,是因为我从来没想过如何在IE保护模式下保存appdata。
#5
5
I've been working with IE's webbrowser control for years now, and over the course of them, one name comes up over and over again with helpful postings: Igor Tandetnik
多年来,我一直在使用IE的网络浏览器控件,在此过程中,有一个名字不断地出现,并提供了有用的信息:Igor Tandetnik
If I were developing an extension, I would target a BHO, and start googling for:
如果我正在开发扩展,我会以一个BHO为目标,并开始在谷歌上搜索:
BHO Igor Tandetnik
BHO Igor Tandetnik
OR
或
Browser Helper Object Igor Tandetnik
浏览器助手对象Igor Tandetnik
His postings are often very detailed, and he knows what he is talking about.
他的帖子往往非常详细,他知道自己在说什么。
You're going to find yourself up to your ears in COM and ATL programming. For a sample walkthrough, check out: http://msdn.microsoft.com/en-us/library/ms976373.aspx
在COM和ATL程序设计中,你会发现自己的耳朵都快到耳朵了。有关示例演练,请参阅:http://msdn.microsoft.com/en-us/library/ms976373.aspx
#6
3
I agree with Robert Harvey, C# 4.0 features improved COM interop. Here's a bit of older C# code, in desperate need of a re-write.
我同意Robert Harvey的观点,c# 4.0特性改进了COM interop。这里有一些旧的c#代码,急需重写。
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
This is an attempt to simplify things by avoiding ATL and going with Spartan COM:
这是一种通过避免ATL和使用Spartan COM来简化事情的尝试:
c++和COM让BHOs运行
#7
3
If you are not trying to reinvent the wheel, you might try Add In Express for IE . I have used the product for the VSTO stuff, and its pretty good. Also they have a helpful forum and quick support.
如果您不尝试重新创建*,您可以尝试为IE添加Express。我用过VSTO类的产品,它相当不错。他们也有一个有用的论坛和快速的支持。
#8
3
It is obviously solved, but for the other users, I would recommend SpicIE framework. I have made my own extension based on it. It only supports Internet Explorer 7/8 officialy, but I tested that on Internet Explorer 6-10 (from Windows XP to Windows 8 Consumer Preview) and it works fine. Unfortunately there were some bugs in the latest release, so I had to fix them and made my own release: http://archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251
显然已经解决了,但是对于其他用户,我推荐SpicIE框架。我已经基于它做了我自己的扩展。它只支持ie7 /8的官方版本,但我在ie6 -10(从Windows XP到Windows 8消费者预览版)上测试过,运行良好。不幸的是,最近的版本中出现了一些错误,所以我不得不修复它们,并制作了自己的版本:http://archive.msdn.microsoft.com/spicie/thread/view.aspx?
#9
0
I warmly suggest you this post of Pavel Zolnikov published in 2002!
我热情地建议您在2002年发表这篇帕维尔·佐尔尼科夫的文章!
http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and
http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and
It is based on the use of Band objects and is compiled using .Net 2.0. Source code is provided and opens and compiles well with Visual Studio 2013. As you will read on the post comments it works perfectly well for IE 11 and on Windows 7 and Windows 10. It worked perfectly well for me on Windows 7 + SP1 and IE 11 Enjoy!
它基于带对象的使用,使用。net 2.0编译。源代码是提供,打开和编译与Visual Studio 2013。正如你在文章评论中看到的那样,它在IE 11、Windows 7和Windows 10上运行得非常好。它在Windows 7 + SP1和IE 11上运行得非常好!
#10
-2
In the Build Events tab, set Post-build events command line to: (x64) is listed below
在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)"
I want the Build Events tab , set Post-build events command line to (32 bit operating system)
我想要Build Events选项卡,将构建后事件命令行设置为(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)"