如何使用BHO定制你的Internet Explorer浏览器

1、简介css

有时,你可能须要一个定制版本的浏览器。在这种状况下,你能够自由地把一些新颖但又不标准的特征增长到一个浏览器上。结果,你最终有的只是一个新但不标准的浏览器。Web浏览器控件只是浏览器的分析引擎。这意味着仍然存在若干的与用户接口相关的工做等待你作――增长一个地址栏,工具栏,历史记录,状态栏,频道栏和收藏夹等。如此,要产生一个定制的浏览器,你能够进行两种类型的编程――一种象微软把Web浏览器控件转变成一个功能齐全的浏览器如Internet Explorer;一种是在现有的基础上加一些新的功能。若是有一个直接的方法定制现有的Internet Explorer该多好?BHO(Browser Helper Objects,我译为"浏览器帮助者对象",如下皆简称BHO)正是用来实现此目的的。shell

2、关于软件定制编程

之前,定制一个软件的行为主要是经过子类化方法实现的。 经过这种办法,你能够改变一个窗口的外表与行为。子类化虽然被认为是一种有点暴力方式――受害者根本不知道发生的事情――但它仍是长时间以来的惟一的选择。api

随着微软Win32 API的到来,进程间子类化再也不被鼓励使用并愈发变得困难起来。固然,若是你是勇敢的--指针从未吓倒你,而最重要的是,若是你已经游刃于系统钩子之间,你可能以为这一问题太简单了。 可是情形并不老是这样。暂放下这点无论,问题在于每个进程运行在本身的地址空间中,并且打破进程边界略微有些不正确性。 另外一方面, 你可能须要对定制进行更好的管理。更常常状况下,定制多是程序自己强烈要求实现的。浏览器

在后者状况下,已安装的软件只需在既定的磁盘位置查询另外的组件模块,而后装载、设定初值,最后让它们自由地按照既定的设计工做。这正是Internet Explorer浏览器和它的BHO所要实现的。安全

3、什么是BHO?服务器

从某种观点看,Internet Explorer同普通的Win32程序没有什么两样。借助于BHO,你能够写一个进程内COM对象,这个对象在每次启动时都要加载。这样的对象会在与浏览器相同的上下文中运行,并能对可用的窗口和模块执行任何行动。例如,一个BHO可以探测到典型的事件,如GoBack、GoForward、DocumentComplete等;另外BHO可以存取浏览器的菜单与工具栏并能作出修改,还可以产生新窗口来显示当前网页的一些额外信息,还可以安装钩子以监控一些消息和动做。简而言之, BHO的工做如咱们打入浏览器领地的一位间谍(注意这是微软容许的合法工做)。框架

在进一步了解BHO细节以前,有几点我须要进一步阐述。首先,BHO对象依托于浏览器主窗口。实际上,这意味着一旦一个浏览器窗口产生,一个新的BHO对象实例就要生成。任何 BHO对象与浏览器实例的生命周期是一致的。其次, BHO仅存在于Internet Explorer 4.0及之后版本中。函数

若是你在使用Microsoft Windows? 98, Windows 2000, Windows 95, or Windows NT版本4.0 操做系统的话,也就一块运行了活动桌面外壳4.71,BHO也被 Windows资源管理器所支持。 BHO是一个COM进程内服务,注册于注册表中某一键下。在启动时,Internet Explorer查询那个键并把该键下的全部对象预以加载。工具

Internet Explorer浏览器初始化这一对象并要求某一接口功能。若是发现这一接口, Internet Explorer使用其提供的方法传递 IUnknown 指针到BHO对象。见图一:

图一 ie浏览器如何装入和初始化BHO对象,BHO场所(site)是用于实现通讯的COM接口

浏览器可能在注册表中发现一系列的CLSID,并由此为每一个CLSID创建一个进程中实例。结果是,这些对象被装载至浏览器上下文中并运行起来,好象它们是本地组件同样。可是,因为Internet Explorer的COM特性,即便被装入到它的进程空间中于事(你的野心实现)也不必定会有多大帮助。用另外一说法, BHO的确可以作许多潜在的有用的事情,如子类化组成窗口或者安装线程局部钩子,可是它确实远离浏览器的核心活动。为了钩住浏览器的事件或者自动化浏览器,BHO须要创建一个私有的基于COM的通信通道。为此,该BHO应该实现一个称为IObjectWithSite的接口。事实上,经过接口IobjectWithSite, Internet Explorer 能够传递它的IUnknown 接口。BHO反过来可以存储该接口并进一步查询更专门的接口,如IWebBrowser二、IDispatch和IConnectionPointContainer。

另一种分析BHO对象的途径与Internet Explorer外壳扩展有关。咱们知道,一个WINDOWS外壳扩展便是一个进程内的COM服务器,它在Windows资源管理器执行某种动做时装入内存――如显示上下文菜单。经过创建一个实现几个COM接口的COM模块,你就给上下文菜单加上一些项并能预以正确处理。一个外壳扩展必须以Windows资源管理器可以发现的方法注册。一个BHO对象遵循一样的模式――惟一的改变在于要实现的接口。然而,尽管实现方式有所不一样,外壳扩展与 BHO 仍有许多共同的特色。以下表一:

表一 外壳扩展与 BHO相近特性比较

特性 外壳扩展 BHO对象
加载者 Windows资源管理器 Internet Explorer(和外壳4.17及以上版本的Windows资源管理器)
击活动做 在某类文档上的用户动做(即单击右键) 打开浏览器窗口
什么时候卸载 参考计数达到0的几秒以后 致使它加载的窗口关闭时
实现形式 COM进程中DLL COM 进程中 DLL
注册需求 经常是为一个COM服务器设置的入口处,另加的入口依赖于外壳类型及它要应用至的文档类型 经常是为一个COM服务器设置的入口处,另加一个把它申请为BHO的注册入口
接口需求 依赖于外壳扩展的类型 IObjectWithSite

若是你对SHELL扩展编程有兴趣的话,能够参考MSDN有关资料。

4、BHO的生存周期

前面已经说过,BHO不只仅为Internet Explorer所支持。若是你在使用外壳 4.71或者更高版本,你的BHO对象也会被Windows资源管理器所加载。下表二展现了咱们可使用的不一样版本的外壳产品状况,Windows外壳版本号存于库文件shell32.dll中。

表二 不一样版本的Windows外壳对于BHO的支持状况

外壳版本 安装的产品 BHO的支持状况
4.00 Windows 95,Windows  NT 4.0 带或不带 Internet Explorer 4.0 或更老版本。 注意没有安装外壳更新 Internet Explorer 4.0
4.71 Windows 95,Windows NT 4.0 带Internet Explorer 4.0 和活动桌面外壳更新 Internet Explorer 与Windows 资源管理器
4.72 Windows 98 Internet Explorer与Windows 资源管理器
5.00 Windows 2000 Internet Explorer与Windows 资源管理器

BHO对象随着浏览器主窗口的显示而装入,随着浏览器主窗口的销毁而缷载。若是你打开多个浏览器窗口,多个BHO实例也一同产生。

不管浏览器以什么样的命令行启动,BHO对象都被加载。举例来讲,即便你只是想要见到特定的 HTML 页或一个给定的文件夹,BHO对象也被加载。通常地,当 explorer.exe 或 iexplore.exe 运行的时候,BHO都要被考虑在内。若是你设置了"Open each folder in its own window"(对每个文件夹以一个独立窗口打开)文件夹选项,那么你每次打开一个文件夹,BHO对象都要被加载。见图二。

图二 通过这样设置,你每次打开一个文件夹时,执行一个独立的explorer.exe实例,并装入已注册的BHO对象。

可是注意,这种情形仅适于当你从桌面上的"个人电脑"图标中打开文件夹的状况。在这种状况下,每次你移到另一个文件夹时外壳都要调用explorer.exe。这种状况在你同时用两个窗格进行浏览时是不会发生的。事实上,当你改变文件夹时,外壳是不会启动浏览器的新的实例的而仅是简单建立嵌入视图对象的另一个实例。奇怪的是,若是你在地址栏中输入一个新的名字来改变文件夹时,在同一个窗口中一样能够达到浏览之目的,不管Windows资源管理器视图是单个的仍是双视图形式。

对于Internet Explorer的情形,事情要更简单一些。只有你显式地屡次运行iexplore.exe浏览器时,你才有多个Internet Explorer的拷贝。当你从Internet Explorer中打开新的窗口时,每个窗口在一个新的线程中被复制而不是建立一个新的进程,所以也就不须要从新载入BHO对象。

首先,BHO最有趣的地方是,它是极度动态的。每次Windows资源管理器或者Internet Explorer打开,装载器从注册表中读取已安装的BHO对象的CLSID而后处理它们。若是你在打开的浏览器多个实例中间编辑注册表的话,你能够随着多个浏览器拷贝的载入而装入多个不一样的BHO。 这就是说,若是你选择从头建立一个新的属于本身的浏览器,那么你能够把它内嵌在一个Visual Basic或者MFC框架窗口中。同时你有至关的机会来灵活安排浏览程序。若是它们能知足你的须要的话,你能够依赖于Internet Explorer的强大的功能而且加上你想要的尽量多的插件。

5、关于IObjectWithSite接口

从一个高起点来看,BHO便是一个DLL,它可以依附于Internet Explorer浏览器的一个新建的实例,在某些状况下也适用于Windows资源管理器。

通常地,一个场所(site)是一个中间对象,它位于容器对象与被包容对象之间。经过它,容器对象管理被包容对象的内容,也所以使得对象的内部功能可用。为此,容器方要实现接口IoleClientSite,被包容对象要实现接口IOleObject 。经过调用IOleObject提供的方法,容器对象使得被包容对象清楚地了解其HOST的环境。

一旦容器对象成为Internet Explorer(或是具备WEB能力的Windows资源管理器),被包容对象只需实现一个轻型的IObjectWithSite接口。该接口提供了如下方法:

表三 IObjectWithSite定义

方法 描述
HRESULT SetSite(IUnknown* pUnkSite) 接收ie浏览器的IUnknown指针。典型实现是保存该指针以备未来使用。.
HRESULT GetSite(REFIID riid, void** ppvSite) 从经过SetSite()方法设置的场所中接收并返回指定的接口,典型实现是查询前面保存的接口指针以进一步取得指定的接口。

对BHO 的惟一严格的要求正在于必须实现这一个接口。 注意你应该避免在调用以上任何一个函数时返回E_NOTIMPL 。 要么你不实现这一接口,要么应保证在调用这些方法时进行正确地编码。

6、构造本身的BHO对象

一个BHO对象就是一个进程中服务器DLL,选用ATL建立它是再恰当不过的了。咱们选择ATL的另一个缘由是由于它已经提供了缺省的并且提供了IObjectWithSite接口的足够好的实现。另外,在ATL COM 向导本地支持的已定义好的对象类型当中,有一个,就是Internet Explorer对象,这正是一个BHO应该具备的类型。一个 ATL Internet Explorer 对象,事实上是一个简单对象――也就是说,是一个支持IUnknown和自注册,还有接口IObjectWithSite的COM 服务器。若是你在ATL工程中添加一个这样的对象,并调用相应的类CViewSource,你将从向导中获得下列代码:

1. class ATL_NO_VTABLE CViewSource :
2. public CComObjectRootEx,
3. public CComCoClass,
4. public IObjectWithSiteImpl,
5. public IDispatchImpl

正如你所见,向导已经使类从接口IObjectWithSiteImpl继承,这是一个ATL模板类,它提供了接口IObjectWithSite的基本实现。通常状况下,没有必要重载成员函数GetSite()。取而代之的是, SetSite() 实现代码常常须要加以定制。ATL实际上仅仅把一个IUnknown接口指针存储在成员变量m_spUnkSite中。

在文章的剩余部分,我将讨论一个 BHO 的至关复杂而丰富的例子。该BHO对象将依附于Internet Explorer,并显示一个文本框来显示当前正浏览的网页源码。 该代码窗口将 随着你改变网页而自动更新,若是浏览器显示的不是一个HTML网页时,它将变灰。你对于原始HTML代码的任何改动当即反映在浏览器中。HTML (DHTML)使得这一看似魔术般的实现成为可能。该代码窗口可被隐藏和经过按动热键重现。 在可见状况下,它与Internet Explorer共享整个桌面空间,见图三。

图三 BHO对象在使用中。它依附于Internet Explorer,并显示一个窗口来显示当前正浏览的网页源码。还容许你源码进行修改。

本例子的关键点在于存取Internet Explorer的浏览机制,其实它只不过是WebBrowser控件的一个实例而已。这个例子能够分解为如下五步来实现:

1.探测谁在装入这个对象,是Internet Explorer仍是Windows资源管理器;

2.获取接口IWebBrowser2以实现Web浏览器对象;

3.捕捉Web浏览器的特定事件;

4.存取当前文档对象,肯定它是一份HTML类型的文件;

5.管理对话框窗口以实现HTML源码的显示;

第一个步骤是在DllMain()中完成的。SetSite()是取得指向WebBrowser对象指针的适当位置。请详细分析如下步骤。

7、探测谁在调用这个对象

如前所述,一个BHO对象会被Internet Explorer或者Windows资源管理器(前提:外壳版本4.71或者更高)所加载。因此我专门设计了一个BHO来处理HTML网页,所以这个BHO与资源管理器毫无关系。若是一个Dll不想被调用者一块儿加载,只需在DllMain()中实现了探明谁在调用该对象后返回FALSE便可。参看下面代码:

01. if (dwReason == DLL_PROCESS_ATTACH)
02. {
03. TCHAR pszLoader[MAX_PATH];
04.  
05. //返回调用者模块的名称,第一个参数应为NULL,详见msdn。
06. GetModuleFileName(NULL, pszLoader, MAX_PATH);
07. _tcslwr(pszLoader);
08. if (_tcsstr(pszLoader, _T("explorer.exe")))
09. return FALSE;
10. }

一旦知道了当前进程是Windows资源管理器,可当即退出。

注意,再多加一些条件语句是危险的!事实上,另一些进程试图装入该DLL时将被放弃。若是你作另一个试验,比方说针对Internet Explorer的执行文件iexplorer.exe,这时第一个受害者就是regsvr32.exe(该程序用于自动注册对象)。

1. if (!_tcsstr(pszLoader, _T("iexplore.exe")))

你不可以再次注册该DLL库了。 事实上,当 regsvr32.exe 试图装入DLL以激活函数DllRegisterServer()时,该调用将被放弃。

8、与Web浏览器取得联系

SetSite()方法正是BHO对象被初始化的地方,此外,在这个方法中你能够执行全部的仅仅容许发生一次的任务。当你用Internet Explorer打开一个URL时,你应该等待一系列的事件以确保要求的文档已彻底下载并被初始化。惟有在此时,你才能够经过对象模型暴露的接口(若是存在的话)存取文档内容。这就是说你要取得一系列的指针。第一个就是指向IWebBrowser2(该接口用来生成WebBrowser对象)的指针。第二个指针与事件有关。该模块必须做为一个浏览器的事件侦听器来实现,目的是为接收下载以及与文档相关的事件。下面用ATL灵敏指针加以封装:

1. CComQIPtr< IWebBrowser2, &IID_IWebBrowser2> m_spWebBrowser2;
2. CComQIPtr m_spCPC;

源代码部分以下所示:

01. HRESULT CViewSource::SetSite(IUnknown *pUnkSite)
02. {
03. // 检索并存储 IWebBrowser2 指针
04. m_spWebBrowser2 = pUnkSite;
05. if (m_spWebBrowser2 == NULL)
06. return E_INVALIDARG;
07. //检索并存储 IConnectionPointerContainer指针
08. m_spCPC = m_spWebBrowser2;
09. if (m_spCPC == NULL)
10. return E_POINTER;
11. //检索并存储浏览器的句柄HWND. 而且安装一个键盘钩子备后用
12. RetrieveBrowserWindow();
13. // 为接受事件通知链接到容器
14. return Connect();
15. }

为了取得IWebBrowser2接口指针,你能够进行查询。固然也能够在事件刚刚发生时查询IConnectionPointContainer。这里,SetSite()检索了浏览器的句柄HWND,而且在当前线程中安装了一个键盘钩子。HWND用于后面Internet Explorer窗口的移动或尺寸调整。这里的钩子用来实现热键功能,用户能够按动热键来显示/隐藏代码窗口。

9、从Internet Explorer浏览器取得事件

当你导向一个新的URL时,浏览器最须要完成的是两种事件:下载文档并为之准备HOST环境。也就是说,它必须初始化某对象并使该对象从外部能够利用。针对不一样的文档类型,或者装入一个已注册的Microsoft ActiveX? 服务器来处理该文档(如Word对于.doc文件的处理)或者初始化一些内部组件来分析文档内容并生成和显示该文档。对于HTML网页就是这样,其内容因为DHTML对象做用而变得可用。当文档所有下载结束,DownloadComplete事件被激活。这并非说,这样利用对象模型就能够安全地管理文档的内容了。事实上,DocumentComplete 事件仅指明一切已经结束,文档已准备好了 (注意DocumentComplete事件仅在你第一次存取URL时到达,若是你执行了刷新动做,你仅仅收到一个DocumentComplete事件)。

为了截获浏览器发出的事件, BHO须要经过IConnectionPoint 接口链接到浏览器上 而且实现传递接口IDispatch指针以处理各类事件。如今利用前面取得的IConnectionPointContainer指针来调用FindConnectionPoint方法――它返回一个指针指向链接点对象(正是经过这个链接点对象来取得要求的外向接口,此时是DIID_DWebBrowserEvent2)。 下列代码显示了链接点的发生状况:

01. HRESULT CViewSource::Connect(void)
02. {
03. HRESULT hr;
04. CComPtr spCP;
05. //为Web浏览器事件而接收(receive)链接点
06. hr = m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvent2, &spCP);
07. if (FAILED(hr))
08. return hr;
09. // 把事件处理器传递到容器。每次事件发生容器都将激活咱们实现的IDispatch接口上的相应的函数。
10. hr = spCP->Advise( reinterpret_cast(this), &m_dwCookie);
11. return hr;
12. }

经过调用接口IConnectionPoint的Advise() 方法, BHO告诉浏览器它对它产生的事件很感兴趣。 因为COM事件处理机制,全部这些意味着BHO把IDispatch接口指针提供给浏览器。浏览器将回调IDispatch接口的Invoke() 方法,以事件的ID值做为第一参数:

01. HRESULT CViewSource::Invoke(DISPID dispidMember, REFIID riid,
02. LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
03. VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
04. {
05. if (dispidMember == DISPID_DOCUMENTCOMPLETE) {
06. OnDocumentComplete();
07. m_bDocumentCompleted = true;
08. }
09. :
10. }

切记,当事件再也不须要时,应该使之与浏览器分离。若是你忘记了作这件事情,BHO对象将被锁定,即便在你关闭浏览器窗口以后。很明显,实现分离的最佳时机是收到事件OnQuit时。

10、存取文档对象

此时,该BHO已经有一个参照指向Internet Explorer的Web浏览器控件并被链接到浏览器控件以接收全部它产生的事件。当网页被所有下载并正确初始化后,咱们就能够经过DHTML文档模型存取它。Web浏览器的文档属性返回一个指向文档对象的IDispatch接口的指针:

1. CComPtr pDisp;
2. HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);

get_Document() 方法取得的仅仅是一个接口指针。咱们要进一步肯定在IDispatch 指针背后存在一个HTML文档对象。用VB实现的话,能够用下面代码:

1. Dim doc As Object
2. Set doc = WebBrowser1.Document
3. If TypeName(doc)="HTMLDocument" Then
4. '' 获取文档内容并予以显示
5. Else
6. '' Disable the display dialog
7. End If

如今要了解一下get_Document()返回的IDispatch指针 。Internet Explorer不只仅是一个HTML浏览器,并且仍是一个ActiveX文档容器。 这样一来,难以保证当前浏览对象就是一个HTML文档。不过办法仍是有的――你想,若是IDispatch指针真正指向一个HTML文档,查询IHTMLDocument2 接口必定成功。
IHTMLDocument2接口包装了DHTML对象模型用来展示HTML页面的全部功能。下面代码实现这些功能:

01. CComPtr pDisp;
02. HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
03. CComQIPtr spHTML;
04. spHTML = pDisp;
05. if (spHTML) {
06. // 获取文档内容并予以显示
07. }
08. else {
09. // disable the Code Window controls
10. }

若是IHTMLDocument2接口查询失败,spHTML指针将是NULL。

如今考虑如何得到当前显示窗口的源代码。正如一个HTML页把它全部的内容封装在标签中,DHTML对象模型要求你取得一个指向Body对象的指针:

1. CComPtr m_pBody;
2. hr = spHTML->get_body(&m_pBody);

奇怪的是,DHTML对象模型不让你取得标签以前的原始内容,如。其内容被处理并存于一些属性中,但你仍是不能从HTML原始文件中提取这部分的RAW文本。这过,仅从BODY部分取得的内容足够了。为了取得包含在…间的HTML代码部分,能够把outerHTML属性内容读取到一个BSTR变量中:

1. BSTR bstrHTMLText;
2. hr = m_pBody->get_outerHTML(&bstrHTMLText);

在此基础上,在代码窗口中显示源码就是一种简单的事情了:生成一个窗口,进行字符的UNICODE至ANSI转化和设置编辑框控件的问题。下面代码实现这些功能:

01. HRESULT CViewSource::GetDocumentContent()
02. {
03. USES_CONVERSION;
04.  
05. // 获取 WebBrowser的文档对象
06. CComPtr pDisp;
07. HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
08. if (FAILED(hr))
09. return hr;
10.  
11. // 确保咱们取得的是一个IHTMLDocument2接口指针
12. //让咱们查询一下 IHTMLDocument2 接口 (使用灵敏指针)
13. CComQIPtr spHTML;
14. spHTML = pDisp;
15.  
16. // 抽取文档源代码
17. if (spHTML)
18. {
19. // 取得BODY 对象
20. hr = spHTML->get_body(&m_pBody);
21. if (FAILED(hr))
22. return hr;
23. // 取得HTML 文本
24. BSTR bstrHTMLText;
25. hr = m_pBody->get_outerHTML(&bstrHTMLText);
26. if (FAILED(hr))
27. return hr;
28. // 进行文本的Unicode到 ANSI的转换
29. LPTSTR psz = new TCHAR[SysStringLen(bstrHTMLText)];
30. lstrcpy(psz, OLE2T(bstrHTMLText));
31. // 文本进行相应的调整
32. HWND hwnd = m_dlgCode.GetDlgItem(IDC_TEXT);
33. EnableWindow(hwnd, true);
34. hwnd = m_dlgCode.GetDlgItem(IDC_APPLY);
35. EnableWindow(hwnd, true);
36.  
37. // 设置代码窗口中的文本
38. m_dlgCode.SetDlgItemText(IDC_TEXT, psz);
39. delete [] psz;
40. }
41. else   // 文档不是一个 HTML 页
42. {
43. m_dlgCode.SetDlgItemText(IDC_TEXT, "");
44. HWND hwnd = m_dlgCode.GetDlgItem(IDC_TEXT);
45. EnableWindow(hwnd, false);
46. hwnd = m_dlgCode.GetDlgItem(IDC_APPLY);
47. EnableWindow(hwnd, false);
48. }
49.  
50. return S_OK; 
51. }

由于我要运行这段代码来响应DocumentComplete事件通知,每一个新的页自动地并且敏捷地被处理。DHTML对象模型使你可以随意修改网页的结构,但这一变化在按F5刷新后所有复原。你还要处理一下DownloadComplete事件以刷新代码窗口 (注意, DownloadComplete 事件发生在 DocumentComplete事件以前)。你应该忽略网页的首次DownloadComplete事件,而是在执行刷新动做时才关注这一事件。布尔成员变量m_bDocumentCompleted正是用来区别这两种情形的。

11、管理代码窗口

用来显示当前HTML页原始码的代码窗口涉及另一个ATL 基本编程问题-对话框窗口,它位于ATL对象向导的"Miscellaneous"选项卡下。

我调整了代码窗口的大小来响应WM_INITDIALOG消息,使它占居桌面空间的下部区域,正好是在任务栏的上面。在浏览器启动时你能够选择显示或不显示这个窗口。缺省状况下是显示的,但这能够经过清除"Show window at startup"复选框项来实现。固然喜欢的话,你能够随时关闭。按键F12便可从新显示代码窗口。F12是经过在SetSite()中安装的键盘钩子实现的。启动环境存于WINDOWS注册表中,我选择外壳库文件shlwapi.dll中函数SHGetValue来实现注册表的读写操做。这同使用Reg开头的Win32函数操做相比,简单极了。请看:

1. DWORD dwType, dwVal;
2. DWORD dwSize = sizeof(DWORD);
3. SHGetValue(HKEY_CURRENT_USER, _T("Software\\MSDN\\BHO"), _T("ShowWindowAtStartup"), &dwType, &dwVal, &dwSize);

这个DLL文件是同Internet Explorer 4.0 和活动桌面的诞生一块儿产生的,是WIN98及之后版本的标准组成,你能够放心使用。

12、注册BHO对象

由于BHO 是一个COM 服务器,因此既应该做为COM 服务器注册又应该做为BHO对象注册。ATL向导自动生成.rgs文件,第一种状况的注册就免除了。下面的文件代码段是用来实现做为BHO对象注册的(CLSID为例中生成)。

01. HKLM {
02. SOFTWARE {
03. Microsoft {  
04. Windows {
05. CurrentVersion {
06. Explorer {
07. ''BHO'' {
08. ForceRemove {1E1B2879-88FF-11D2-8D96-D7ACAC95951F}       
09. }}}}}}}

注意ForceRemove一词可以实如今卸载对象时删除这一行相应的键值。BHO键下汇集了全部的BHO对象。对于这么多的一串家伙是历来不做缓冲调用的。这样以来,安装与测试BHO就是不费时的事情了。

十3、总结

本文描述了BHO对象,经过它你能够把本身的代码注入浏览器的地址空间中。你必须作的事情是写一个支持IObjectWithSite 接口的COM 服务器。在这一点上,你的BHO对象能够实现浏览器机制范围内的各类合法目的。本文所及示例涉及了COM事件,DHTML对象模型以及WEB浏览器编程接口。虽然内容稍宽一些,但它正显示了现实世界中的BHO对象的应用。如,你想知道浏览器在显示什么,那么您就须要了解接收事件并要熟悉WEB浏览器才行。

另外:Windows资源管理器也是与BHO对象交互的,这一点在编程时要特别注意。本文所附源程序为MSDN所带,在Windows2000/VC6下调试经过(编译经过后,从新启动IE即获得结果)。

相关文章
相关标签/搜索