IObjectWithSite 接口
从这个高层来看待浏览器助手对象,一个概念就清晰的显现出来了:BHO 是一个动态连接库 (DLL),它能附着在 Internet Explorer 的一个新实例上,在某些情况下,也能附着在 Windows Explorer 的实例上。这样的模块能通过容器的现场与浏览器建立联系。
通常,现场是指处于容器和每个被包含的对象之间的中介对象。容器通过它管理包含的对象,并随后使对象的内置功能可用。这种容器和对象之间的基于现场的关系涉及到在容器一端实现像 IOleClientSite 这样的接口,以及在对象一端实现像 IOleObject 这样的接口。通过调用 IOleObject 上的方法,容器使对象知道它的宿主环境。
当容器是 Internet Explorer (或支持 Web 的 Windows Explorer),从性能的角度考虑,需用将这种通讯模式降低到必要的程度。现在对象需要实现更简单更小的叫作 IObjectWithSite 的接口。它只需提供两个方法。
表 3. IObjectWithSite 接口定义
对 BHO 的唯一严格要求就是实现这个接口。注意你要避免从前面所说的函数中返回 E_NOTIMPL。你要么不去实现这个接口,要么正确地编写它的方法。
编写浏览器助手对象
浏览器助手对象是进程内的 COM 服务程序,那么还有什么比 Active Template Library (ATL)更适合用来编写它呢?选择 ATL 的另一个原因是它已经默认提供了一个很好的 IObjectWithSite 接口。还有,在 ATL COM 向导内置支持的预定义对象类型中,有一个 Internet Explorer 对象,正好是 BHO 的对象类型。实际上,ATL Internet Explorer 对象是一个简单的对象。就是说,一个 COM 服务程序,支持 IUnknown 和自我注册加上 IObjectWithSite。如果你在 ATL 项目中添加一个这样的对象,并引用 CViewSource 类,你可以从向导中得到以下代码:
class ATL_NO_VTABLE CViewSource :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CViewSource, &CLSID_ViewSource>,
public IObjectWithSiteImpl<CViewSource>,
public IDispatchImpl<IViewSource, &IID_IViewSource,
&LIBID_HTMLEDITLib>
像你看到的那样,向导已经使这个类继承 IObjectWithSiteImpl,它是提供 IObjectWithSite 的基本实现的一个 ATL 模板类。(参见 Microsoft Visual Studio 98 中 ATLINCLUDE 目录下的 atlcom.h。) 通常不需要重载 GetSite() 成员函数。相反,GetSite() 的已有代码常常(即使并不总是)需要按用户要求来重写。实际上,ATL 只是简单地将 IUnknown 指针保存到一个叫 m_spUnkSite 的成员变量里。