探索浏览器扩展:BHO与Band对象的实现与应用
1. 浏览器辅助对象(BHO)的实现与应用
BHO 是一种在浏览器进程内运行的扩展,能让开发者在不依赖 UI 的情况下访问 IE 的事件和功能。下面将详细介绍其实现与应用。
1.1 BHO 的注销功能
要移除 BHO,可使用以下代码注销关联的注册表项:
[ComUnregisterFunction]
public static void Unregister(Type type)
{
// Open up the main BHO key
RegistryKey bhoKey =
Registry.LocalMachine.OpenSubKey(
@"Software\Microsoft\Windows\CurrentVersion\" +
@"Explorer\Browser Helper Objects",
true);
// Delete the GUID key if it exists
if (bhoKey != null) bhoKey.DeleteSubKey(
type.GUID.ToString("B"), false);
}
移除注册表项后,IE 不再加载该 BHO,也不会在“管理加载项”对话框中显示。
1.2 捕获浏览器事件
BHO 不仅能加载到浏览器进程,还可通过
SetSite
方法获取
WebBrowser
实例,进而利用其丰富的功能。其中,捕获浏览器事件是重要应用之一。常见且实用的事件由
DWebBrowserEvents2
接口暴露,如
BeforeNavigate2
(导航前触发)、
NavigationComplete2
(导航完成时触发)和
DocumentComplete
(文档完全加载时触发)。
以下是在
SetSite
调用中捕获事件的示例:
[SecurityPermission(SecurityAction.LinkDemand,
Flags = SecurityPermissionFlag.UnmanagedCode),
ComVisible(true),
Guid("FE19878E-55B9-48AA-B293-2BDEEB2232DB"),
ClassInterface(ClassInterfaceType.None)]
public class BhoSampleEvents : NativeMethods.IObjectWithSite
{
...
public int SetSite(object site)
{
// If the site is valid, cast as a WebBrowser object and
// store it in the Browser variable
if (site != null)
{
// Set the site object, cast as a WebBrowser object,
// to the Browser variable
Browser = (SHDocVw.WebBrowser)site;
// Add a handler for when navigation starts
Browser.BeforeNavigate2 += Browser_BeforeNavigate2;
// Add a handler for when the document has completely loaded
Browser.DocumentComplete += Browser_DocumentComplete;
}
else
{
// Detatch the event handlers if they were attached
Browser.BeforeNavigate2 -= Browser_BeforeNavigate2;
Browser.DocumentComplete -= Browser_DocumentComplete;
// Set the browser object to null
Browser = null;
}
return S_OK;
}
}
1.3 事件回调函数
- BeforeNavigate2 事件回调 :
void Browser_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object
TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
{
// If the site or url is null, do not continue
if (pDisp == null || URL == null) return;
// Convert the url object reference to a string
string url = URL.ToString();
// Show the url in a message box
MessageBox.Show("Begin navigation to: " + url);
}
该函数在特定标签页导航前显示包含目标 URL 的消息框。
- DocumentComplete 事件回调 :
void Browser_DocumentComplete(object pDisp, ref object URL)
{
// If the site or url is null, do not continue
if (pDisp == null || URL == null) return;
// Grab the document object off of the WebBrowser control
IHTMLDocument2 document = (IHTMLDocument2)Browser.Document;
if (document == null) return;
// Report the total number of links on the current page
MessageBox.Show("Total links on this page: " +
document.links.length.ToString());
}
此函数在文档加载完成后,显示当前页面的链接总数。
需要注意的是,
DocumentComplete
事件在页面加载时可能会多次触发,每次加载一个框架都会触发一次,最后顶级窗口加载完成时也会触发。开发者可通过比较传递给事件处理程序的
pDisp
指针与顶级窗口的
pDisp
指针来区分。
同时,由于回调函数在 IE UI 线程中运行,运行时会占用用户控制权,因此应尽量减少在这些函数中的处理时间,或另起线程处理事件。
2. 使用 Band 对象扩展浏览器框架
Band 对象为开发者提供了扩展 Windows 外壳和 IE 浏览器框架的途径,能在浏览器界面的显著位置展示内容。下面将介绍三种常见的 Band 对象:工具栏、垂直资源管理器栏和水平资源管理器栏。
2.1 Band 对象概述
IE 提供了三个主要区域用于显示 Band 对象:工具栏区域、窗口左侧(垂直资源管理器栏区域)和窗口底部(水平资源管理器栏区域)。这些对象可在 IE 的“工具”菜单中管理,也能通过“管理加载项”窗口进行管理。关闭 Band 对象时,它们仍会保留在内存中,直到浏览器重启。
2.2 构建通用 Band 对象
所有类型的 Band 对象都基于相同的构建块,包括用户界面和用于连接浏览器、Windows 外壳和 COM 的接口。在 .NET 代码中,主要由通用的
UserControl
和一系列非托管接口组成。
以下是
BandObject
类的基本架构:
public class BandObject : UserControl,
IObjectWithSite,
IDeskBand, IDockingWindow,
IOleWindow
{
#region Static Members ...
#region Instance Members ...
#region Virtual Methods ...
#region IObjectWithSite Interface Implementation ...
#region IOleWindow Interface Implementation ...
#region IDockingWindow Interface Implementation ...
#region IOLECommandTarget Interface Implementation ...
#region COM Registration Methods ...
}
该类可进一步划分为以下几个部分:
-
静态成员
:定义元数据,如大小、标题等,供派生类使用。
#region Static Members
public static string ClassId;
public static string ProgId;
public static string ObjectTitle;
public static string ObjectName;
public static string HelpText;
public static new Size InitialSize;
public static Size MinSize;
public static Size MaxSize;
public static Size IntegralSize;
public static BandObjectTypes Style = BandObjectTypes.HorizontalExplorerBar;
#endregion Static Members
其中,
Style
变量用于定义 Band 对象的类型,通过
BandObjectTypes
枚举指定:
public enum BandObjectTypes
{
VerticalExplorerBar = 1,
Toolbar = 2,
HorizontalExplorerBar = 4
}
-
实例成员
:存储与
IWebBrowser和 IE 应用程序站点的引用。
#region Instance Members
public SHDocVw.WebBrowserClass WebBrowser;
public SHDocVw.InternetExplorer BandObjectSite;
#endregion Instance Members
-
虚拟方法
:
DefineMetadata方法用于设置静态元数据。
#region Virtual Methods
public void DefineMetadata() { }
#endregion Virtual Methods
-
接口实现
:
- IObjectWithSite 接口 :用于获取和设置对象加载的“站点”(COM 对象),即 IE 浏览器对象。
#region IObjectWithSite Interface Implementation
public void SetSite(object pUnkSite)
{
if (!(pUnkSite is SHDocVw.InternetExplorer))
{
if (BandObjectSite != null)
{
Marshal.ReleaseComObject(BandObjectSite);
BandObjectSite = null;
}
return;
}
try
{
BandObjectSite = (SHDocVw.InternetExplorer)pUnkSite;
ProIeDev.BandObjectDemo.Interop.Interfaces.IServiceProvider serviceProvider =
(ProIeDev.BandObjectDemo.Interop.Interfaces.IServiceProvider)
BandObjectSite;
object pUnknown = null;
Guid guid = new Guid(IID.IID_IWebBrowserApp);
Guid riid = new Guid(IID.IID_IUnknown);
serviceProvider.QueryService(ref guid, ref riid, out pUnknown);
WebBrowser = (SHDocVw.WebBrowserClass)Marshal.CreateWrapperOfType(
pUnknown as IWebBrowser, typeof(SHDocVw.WebBrowserClass));
object pvaClsid = (object)ClassId;
object pvarSize = null;
object pvarShowTrue = (object)true;
WebBrowser.ShowBrowserBar(ref pvaClsid, ref pvarShowTrue, ref pvarSize);
}
catch (Exception) { }
}
public void GetSite(ref Guid riid, out object ppvSite)
{
ppvSite = BandObjectSite;
}
#endregion IObjectWithSite Interface Implementation
- **IDeskBand 接口**:用于获取即将加载到 Windows 外壳或 IE 中的 Band 对象的信息。
#region IDeskBand Interface Implementation
public void GetBandInfo(uint dwBandID, uint dwViewMode, ref DESKBANDINFO pdbi)
{
try
{
if ((pdbi.dwMask & DBIM.TITLE) == DBIM.TITLE)
pdbi.wszTitle = ObjectTitle;
if ((pdbi.dwMask & DBIM.ACTUAL) == DBIM.ACTUAL)
{
pdbi.ptActual.X = InitialSize.Width;
pdbi.ptActual.Y = InitialSize.Height;
}
if ((pdbi.dwMask & DBIM.MAXSIZE) == DBIM.MAXSIZE)
{
pdbi.ptMaxSize.X = MaxSize.Width;
pdbi.ptMaxSize.Y = MaxSize.Height;
}
if ((pdbi.dwMask & DBIM.MINSIZE) == DBIM.MINSIZE)
{
pdbi.ptMinSize.X = MinSize.Width;
pdbi.ptMinSize.Y = MinSize.Height;
}
if ((pdbi.dwMask & DBIM.INTEGRAL) == DBIM.INTEGRAL)
{
pdbi.ptIntegral.X = IntegralSize.Width;
pdbi.ptIntegral.Y = IntegralSize.Height;
}
if ((pdbi.dwMask & DBIM.BKCOLOR) == DBIM.BKCOLOR)
pdbi.dwMask &= ~DBIM.BKCOLOR;
if ((pdbi.dwMask & DBIM.MODEFLAGS) == DBIM.MODEFLAGS)
{
pdbi.dwModeFlags = DBIMF.VARIABLEHEIGHT | DBIMF.NORMAL;
if (Style == BandObjectTypes.Toolbar)
pdbi.dwModeFlags |= DBIMF.BREAK | DBIMF.ALWAYSGRIPPER;
}
}
catch (Exception) { }
}
#endregion IDeskBand Interface Implementation
- **IOleWindow 接口**:允许处理 OLE 窗口调用,主要使用 `GetWindow` 方法返回 `UserControl` 实例的窗口句柄。
#region IOleWindow Interface Implementation
public void GetWindow(out IntPtr phwnd)
{
phwnd = Handle;
}
public void ContextSensitiveHelp(bool fEnterMode)
{
return;
}
#endregion IOleWindow Interface Implementation
总结
BHO 和 Band 对象为开发者提供了扩展 IE 功能的有效途径。BHO 能在浏览器进程内运行,捕获浏览器事件,增强页面功能;Band 对象则可扩展浏览器框架,在显著位置展示内容。通过合理运用这些技术,开发者能为用户带来更丰富的浏览器体验。
以下是 BHO 和 Band 对象的特点对比表格:
| 类型 | 运行方式 | 功能特点 | 应用场景 |
| ---- | ---- | ---- | ---- |
| BHO | 进程内运行 | 捕获浏览器事件,无需 UI | 监控页面加载、导航等事件 |
| Band 对象 | 扩展浏览器框架 | 提供 UI 展示,可在工具栏、侧边栏等位置显示 | 增强浏览器界面功能 |
mermaid 流程图展示 BHO 事件处理流程:
graph LR
A[浏览器事件触发] --> B{事件类型}
B -->|BeforeNavigate2| C[调用 BeforeNavigate2 回调]
B -->|DocumentComplete| D[调用 DocumentComplete 回调]
C --> E[显示导航信息]
D --> F[显示页面链接数量]
以上就是关于 BHO 和 Band 对象的详细介绍,希望能帮助开发者更好地扩展浏览器功能。
探索浏览器扩展:BHO与Band对象的实现与应用(续)
3. BHO与Band对象的实际应用案例分析
在实际开发中,BHO和Band对象有着广泛的应用场景,下面通过具体案例来进一步了解它们的实际用途。
3.1 BHO的实际应用
-
广告拦截
:利用BHO捕获
DocumentComplete事件,在页面加载完成后,通过分析页面的DOM结构,查找并移除广告元素。以下是一个简单的示例代码:
void Browser_DocumentComplete(object pDisp, ref object URL)
{
if (pDisp == null || URL == null) return;
IHTMLDocument2 document = (IHTMLDocument2)Browser.Document;
if (document == null) return;
// 查找并移除广告元素
IHTMLElementCollection elements = document.all;
for (int i = elements.length - 1; i >= 0; i--)
{
IHTMLElement element = (IHTMLElement)elements.item(i, 0);
if (element.className != null && element.className.Contains("ad"))
{
element.parentNode.removeChild(element);
}
}
}
-
页面性能监测
:在
BeforeNavigate2事件中记录开始时间,在DocumentComplete事件中记录结束时间,计算页面加载时间。
DateTime startTime;
void Browser_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object
TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
{
if (pDisp == null || URL == null) return;
startTime = DateTime.Now;
}
void Browser_DocumentComplete(object pDisp, ref object URL)
{
if (pDisp == null || URL == null) return;
DateTime endTime = DateTime.Now;
TimeSpan loadTime = endTime - startTime;
MessageBox.Show("页面加载时间: " + loadTime.TotalSeconds + " 秒");
}
3.2 Band对象的实际应用
-
自定义工具栏
:创建一个包含常用功能按钮的工具栏,如刷新、收藏、分享等。通过继承
BandObject类,设置相应的静态成员和实现接口方法。
public class CustomToolbar : BandObject
{
public CustomToolbar()
{
// 初始化工具栏按钮
Button refreshButton = new Button();
refreshButton.Text = "刷新";
refreshButton.Click += RefreshButton_Click;
this.Controls.Add(refreshButton);
}
private void RefreshButton_Click(object sender, EventArgs e)
{
if (WebBrowser != null)
{
WebBrowser.Refresh();
}
}
public override void DefineMetadata()
{
ClassId = "{YOUR_CLASS_ID}";
ProgId = "CustomToolbar";
ObjectTitle = "自定义工具栏";
ObjectName = "CustomToolbar";
HelpText = "这是一个自定义工具栏";
InitialSize = new Size(200, 30);
MinSize = new Size(100, 30);
MaxSize = new Size(500, 30);
IntegralSize = new Size(10, 0);
Style = BandObjectTypes.Toolbar;
}
}
- 侧边栏信息展示 :创建一个垂直资源管理器栏,用于展示网站的相关信息,如文章列表、热门标签等。
public class SidebarInfo : BandObject
{
public SidebarInfo()
{
// 初始化侧边栏内容
ListBox articleList = new ListBox();
articleList.Items.Add("文章1");
articleList.Items.Add("文章2");
this.Controls.Add(articleList);
}
public override void DefineMetadata()
{
ClassId = "{YOUR_CLASS_ID}";
ProgId = "SidebarInfo";
ObjectTitle = "侧边栏信息";
ObjectName = "SidebarInfo";
HelpText = "展示网站相关信息";
InitialSize = new Size(200, 400);
MinSize = new Size(100, 200);
MaxSize = new Size(300, 600);
IntegralSize = new Size(10, 10);
Style = BandObjectTypes.VerticalExplorerBar;
}
}
4. 开发注意事项与技巧
在开发BHO和Band对象时,需要注意以下几点:
-
性能优化
:如前文所述,BHO的回调函数在IE UI线程中运行,应尽量减少处理时间,避免影响用户体验。可以采用异步处理或多线程的方式来处理复杂任务。
-
兼容性问题
:不同版本的IE可能对BHO和Band对象的支持有所不同,开发时需要进行充分的测试,确保在各种版本的IE中都能正常工作。
-
错误处理
:在代码中添加适当的错误处理机制,避免因异常情况导致浏览器崩溃或功能失效。
以下是一个简单的错误处理示例:
void Browser_DocumentComplete(object pDisp, ref object URL)
{
try
{
if (pDisp == null || URL == null) return;
IHTMLDocument2 document = (IHTMLDocument2)Browser.Document;
if (document == null) return;
MessageBox.Show("Total links on this page: " +
document.links.length.ToString());
}
catch (Exception ex)
{
MessageBox.Show("发生错误: " + ex.Message);
}
}
5. 总结与展望
BHO和Band对象为开发者提供了强大的浏览器扩展能力,通过捕获浏览器事件和扩展浏览器框架,可以实现各种个性化的功能。在未来的浏览器开发中,随着技术的不断发展,浏览器扩展的功能将更加丰富和强大。
以下是BHO和Band对象开发的步骤总结表格:
| 类型 | 开发步骤 |
| ---- | ---- |
| BHO | 1. 实现BHO类;2. 注册BHO;3. 捕获浏览器事件;4. 实现事件回调函数 |
| Band对象 | 1. 继承
BandObject
类;2. 设置静态成员元数据;3. 实现接口方法;4. 初始化UI内容 |
mermaid 流程图展示Band对象的开发流程:
graph LR
A[创建Band对象类] --> B[设置静态成员元数据]
B --> C[实现接口方法]
C --> D[初始化UI内容]
D --> E[注册Band对象]
通过本文的介绍,相信开发者对BHO和Band对象有了更深入的了解,能够在实际开发中灵活运用这些技术,为用户带来更好的浏览器体验。
超级会员免费看
854

被折叠的 条评论
为什么被折叠?



