前言:
本文档是为了演示如何使用V2005开发一个简单的BHO组件,BHO组件是实现了IObjectWithSite接口的
COM对象,该COM对象与IE进行绑定。
本文档将逐步演示如何建立BHO组件的过程,该组件实现的功能:首先当装载WEB页的时候
打印出"Hello world"信息,然后把该WEB页的所有图片资源删除。
内容提纲:
简单介绍
概要介绍
建立项目
实现基本应用
对事件进行响应
处理DOM
总结
相关参考资料
简单介绍
上述功能的实现主要使用V2005和ATL技术,我们之所以使用ATL的愿意在于它提供了一个方便扩展的模板文件。其实还有其他方法可以建立BHO,例如MFC,WIN32 API和COM等技术,但是ATL是一个轻量级的库它提供了很多内置的功能为我们处理底层的诸多细节实现,例如将为我们自动注册BHO的CLSID。
ATL的另一个优点是支持智能指针的类(例如CComPtr 和CComBSTR),这些智能指针类将起到管理COM
生命周期的作用。例如,CComPtr通过调用AddRef方法来进行赋值操作,而通过调用Release来对对象进行
销毁操作。智能指针简化了代码,并且提供了检测内存错误的功能,它们提供的安全性和稳定性在方法内非常有用。
文章的第一部分将演示如何实现一个简单的BHO组件,并且确认在IE启动的时候该组件被执行。
文章的第二部分则演示如何把BHO组件与浏览器事件进行关联,文档的最后一部分则是一个把该
组件与 DOM关联来修改WEB页面的功能。
概要介绍
什么是BHO?BHO是一个组件,是个轻量级的DLL扩展,提供了向IE增加新功能的途径。尽管BHO使用的
比较少,并且不是本文档的重点内容,但是BHOs还可以向WINDOWS EXplorer添加新的功能扩展。
BHOs不会提供任何界面,它们常常运行在后台,捕获IE事件与用户的输入。例如,BHOs可以阻塞弹出
菜单,可以自动填充表单,可以对光标进行捕获等。认为BHOs仅仅是为了扩展工具条的功能是个普遍的错误认识,然而,BHOs与工具条的联合使用可以提供富客户端的用户体验。
提示:BHOs是一个很方便的工具对于用户和开发者来说;但是因为BHOs被赋予的权限超过了浏览器
本身的权限要求,而且它们的运行常常不容易被探测到,所以我们要确保BHOs的来源是可信任、
的。BHOs的生命周期将与其关联的IE浏览器实例一样长,在IE6之前的版本,这意味着BHO的生成
是在顶层窗口之上的,而在IE7之后的版本则是一个浏览标签TAB页。BHO不能被其他的应用及
HTML的对话框所装载。
BHO最关键的是实现了IObjectWithSite接口,这个接口为我们提供了诸如SetSite等方法,这些
方法提供了与IE交互的途径。我们将生成一个简单的BHO并且在注册表里为其注册个CLSID。
让我们开始吧。
建立一个新项目
1, File->New Project...
对话框里将列表显示出可以用VS生成的项目类型。
2,在{visual c++}节点下选择"ATL",生成一个ATL类型的项目,我们为这个项目起名
为"Hello World"
3,在ATL Project Wizard的项目生成向导中需要确定服务类型为动态连接库
(Dynamic-link library)
在本步VS为我们生成了项目模板,我们需要添加COM对象来实现BHO组件。
1,在Solution Exploerer控制面板里,右键单击,选择class...从Add菜单里。
2,选择"ATL Simple Object"并且点{Add}按纽,则ATL Simple Object Wizard向
导出现。
3,在名字文本框里,写入"HelloWorldBHO.
4,在<Options>的面板上,需要进行确认的选择项如下:
选择"Apartment "对Threading Model.
选择"No"对Aggregation
选择"Dual"对Interface
选择"IObjectWithSite"对Support.
5,点击 {完成按纽}.
出现的文件列表:
HelloWorld.idl--这是个定义COM接口的文件,我们不在这个项目里进行任何修改。
HelloWorld.rgs--这是个包含注册键码的文件,当该DLL被注册或是被解除注册
的时候进行定义。
基础功能
ATL Project Wizard提供了SetSite的默认实现,尽管该方法可以被不限定次数的调
用,但是IE调用该方法仅两次,一次是建立连接的时候,一次是当退出IE的时候。
明确的讲,SetSite主要
完成如下功能:
1,保存对站点的引用。在IE初始化的时候,IE传送一个IUnknown指针到顶层的
top-level的
WebBrowser Control,而BHO则保存对其的引用,该引用保存在一个私有变量里。
2,释放保存的站点指针。当IE传送NULL的时候,BHO必须释放对所有接口的引用,并
且断开与该浏览器对象的连接。
作为SetSite的处理的一部分,BHO仍然可以进行其他的初始操作与释放操作,例如
你希望建立一个与特定浏览器对象的连接,然后检测该浏览器的事件。
HelloWorldBHO.h
首先添加对shlguid.h头文件的包含命令,该文件定义了IWebBrowser2的接口,和
事件。
然后在CHelloWorldBho类的公共变量列表中添加
STDMETHOD(SetSite)(IUnknown *pUnkSite);
STDMETHOD宏是ATL的应用范例,它标志该方法是虚方法,并且确保它被正确调用
最后在私有变量部分声明一个保存浏览器站点的引用变量。
private:
CComPtr<IWebBrowser2>m_spWebBrowser;
HelloWorldBHO.cpp
STDMETHODIMP CHelloWorldBHO::SetSite(IUnknown* pUnkSite)
{
if (pUnkSite != NULL)
{
// Cache the pointer to IWebBrowser2.
pUnkSite->QueryInterface(IID_IWebBrowser2,
(void**)&m_spWebBrowser);
}
else
{
// Release cached pointers and other resources
//here.
m_spWebBrowser.Release();
}
// Return the base class implementation
return IObjectWithSiteImpl<CHelloWorldBHO>::SetSite(pUnkSite);
}
HelloWorld.cpp
当DLL被装载的时候,系统调用DllMain方法,当DLL_PROCESS_ATTACH通知发送的时候。
因为BHO不需要在线程的级别上进行跟踪,所以我们可以调用
DisableThreadLibraryCalls.可以阻止新的线程通知消息。
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
}