BHO(Browser Help Objects),是实现了特定接口的COM组件 开发好的BHO插件在注册表特定的位置注册好后,每当微软的浏览器启动,BHO实例就会被创建。在浏览器工作的工程中,BHO会接收到很多事件,
比如浏览器浏览新的地址、前进或后退、生成新的窗口、浏览器退出等等;BHO可以在这些事件的响应中实现与浏览器的交互。
下面,我们首先来介绍一下BHO的工作原理。上面我们已经提到,BHO是COM组件,而且一定实现了IObjectWithSite接口。这些组件除了在注册表中注册为COM Server外,还必须将它们的CLSID在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/ CurrentVersion/Explorer/Browser Helper Objects下注册为子键 。
微软在设计浏览器的时候,已经给这些组件预留了空间。每当浏览器启动时,浏览器会首先在上述注册表位置查看是否有注册的 BHO CLSID;如果有则分别创建一个实例,并对BHO实例进行初始化,建立交互连接。(注:BHO实例只有在创建它的浏览器窗口销毁时才被释放 。)
原理:
IE将自己的IUnKnown指针传递给BHO,BHO需要建立一个私有的基于COM的通讯通道,目的是响应IE事件。所以BHO最重要的是实现
IObjectWithSite 接口。IE 通过这个接口,传递自己的IUnknown接口,BHO存储该接口,进一步通过调用IObjectWithSite 提供的方法。
IE启动时候会依次执行一些函数,把BHO自己的函数注册到这里,书面上称之为连接点 。这样就能调用进入 BHO自己的程序内部了。IObjectWithSite 主要有两个函数要实现:
- HRESULT SetSite(IUnknown* pUnkSite) 接收ie浏览器的IUnknown指针。典型实现是保存该指针以备将来使用 。
- HRESULT GetSite(REFIID riid, void** ppvSite) 从通过SetSite()方法设置的场所中接收并返回指定的接口,典型实现是查询前面保 存的接口指针以进一步取得指定的接口
成功创建的BHO,不仅可以得到各种标准的浏览器操作事件,并做出响应;还可以定制浏览器的菜单、工具条等界面元素;更或者可以安装钩子函数,监视浏览器的一举一动。值得注意的是,使用BHO插件,Internet浏览器要求在4.0以上版本;如果是文件浏览器 ,操作系统要求是Windows 95/98/2000或Window NT 4.0以上版本,并且Shell的版本在4.71以上。下面是支持BHO特性的系统一览表:
Shell版本 操作系统版本 支持BHO
4.00 Windows 95 and Windows NT 4.0(IE版本为 4.0) 仅IE4.0
4.71 Windows 95 and Windows NT 4.0(IE版本为 4.0) IE和文件浏览器
4.72 Windows 98 IE和文件浏览器
5.00 Windows 2000 IE和文件浏览器
----------------------------------------------------- GO!!! -------------------------------------------------------
a) 首先启动VC 2005 新建工程 ATL Project
工程名字: HelloWorld
Application Settings 中,Server type 选择 Dynamic-link library (dll) 其他都不选。(简单总结为以atl 创建dll工程)
b) 其次在新建好的CLASS VIEW下选择 工程 HelloWorld 右键 add -> class
选择创建ATL Simple Object ,下一步 在short name中输入 HelloWorldBHO 其他都自动补齐不用管。
下一步在options中 :
- Threading mode 选择 Apartment ;
- Aggregation 选择 no;
- Interface 选择 Dual
- support 选择 IObjectWithSite(IE object support)
点击Finish ,这是一个最简单的BHO已经创建好了。
c) 目前要做的就是添砖了
编辑 HelloWorldBHO.h 发现系统已经为你创建了 CHelloWorldBHO类, 在类的最下行有一个public: 没后文,这里就是系统提示你要添加的代码了。
CHelloWorldBHO 中SetSite 已经为你添加将浏览器的IUnknown 指针保存下来(见m_spUnkSite);
现在要做的是注册到连接点。
继承父类的 SetSite方法,显示调用父类(SetSite)方法,添加一个注册函数。(就是前面所述的,添加到连接点)
其中成员声明:
DWORD mCookie; 连接点注册上去的索引,方便以后反注册使用。
CComQIPtr<IWebBrowser2> m_spWebBrowser2;
m_spWebBrowser2 用来将浏览器IUnknown 指针转变为 IWebBrowser2 ,并保存方便后面使用。
我们可以看到将 IDispatch 接口注册上去了。
查IDispatch 接口,主要核心在于实现 Invoke 函数。
上面是这次实例的范例代码。有兴趣的朋友可以照着敲下,下面还是讲下这个函数里面的一些点:
I.最佳反注册时机
case DISPID_QUIT:
RegisterEventHandler(FALSE);
在浏览器退出的时候,是最佳反注册时机,不然可能浏览器退出后,你的BHO还在运行哦(有可能)
II. 有些宏需要引入头文件
#include <exdisp.h >
#include <ExDispid.h>
III.当要使用ATL 编码转换时候在函数开头引入 USES_CONVERSION; 宏,不过这里如果没有转换应用,可以去掉。
根据支持BHO特性,为了不让资源管理器加载该BHO,所以在dll main 函数里加入如下代码判断是否加载: