VC++开发BHO插件定制你的浏览器.docx
- 文档编号:8000761
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:18
- 大小:72.53KB
VC++开发BHO插件定制你的浏览器.docx
《VC++开发BHO插件定制你的浏览器.docx》由会员分享,可在线阅读,更多相关《VC++开发BHO插件定制你的浏览器.docx(18页珍藏版)》请在冰豆网上搜索。
VC++开发BHO插件定制你的浏览器
文章原始出处
正文
在Windows操作系统上,我们最常见的浏览器有两种:
文件浏览器(exploer.exe,应用于文件系统)和Internet浏览器(iexplore.exe,应用于互联网资源)。
由于这两个浏览器功能强大,而且又与Windows操作系统捆绑销售,最终也就成为了浏览器的标准。
但有时候,为了给浏览器加入一些新的特性,我们往往会重新设计一个自己的浏览器。
新的浏览器模仿标准浏览器的大部分功能,同时加入新特性。
这种做法最直观,但实际上也是相对于微软的重复劳动,且工作量比较大。
其实,使用BHO插件,一切都变得很简单。
BHO(BrowserHelpObjects),是实现了特定接口的COM组件。
开发好的BHO插件在注册表特定的位置注册好后,每当微软的浏览器启动,BHO实例就会被创建。
在浏览器工作的工程中,BHO会接收到很多事件,比如浏览器浏览新的地址、前进或后退、生成新的窗口、浏览器退出等等;BHO可以在这些事件的响应中实现与浏览器的交互。
下面,我们首先来介绍一下BHO的工作原理。
上面我们已经提到,BHO是COM组件,而且一定实现了IObjectWithSite接口。
这些组件除了在注册表中注册为COMServer外,还必须将它们的CLSID在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\BrowserHelperObjects下注册为子键。
微软在设计浏览器的时候,已经给这些组件预留了空间。
每当浏览器启动时,浏览器会首先在上述注册表位置查看是否有注册的BHOCLSID;如果有则分别创建一个实例,并对BHO实例进行初始化,建立交互连接。
(注:
BHO实例只有在创建它的浏览器窗口销毁时才被释放。
)下图演示了BHO的创建过程:
成功创建的BHO,不仅可以得到各种标准的浏览器操作事件,并做出响应;还可以定制浏览器的菜单、工具条等界面元素;更或者可以安装钩子函数,监视浏览器的一举一动。
值得注意的是,使用BHO插件,Internet浏览器要求在4.0以上版本;如果是文件浏览器,操作系统要求是Windows95/98/2000或WindowNT4.0以上版本,并且Shell的版本在4.71以上。
下面是支持BHO特性的系统一览表:
Shell版本操作系统版本支持BHO
4.00Windows95andWindowsNT4.0(IE版本为4.0)仅IE4.0
4.71Windows95andWindowsNT4.0(IE版本为4.0)IE和文件浏览器
4.72Windows98IE和文件浏览器
5.00 Windows2000IE和文件浏览器
接下去,笔者就来介绍一下如何开发BHO插件,开发环境为VC6.0(使用ATL),安装PlatformSDK中的InternetDevelopmentSDK。
首先,启动VC的ATLCOMAppWizard,生成一个项目名为BhoPlugin,其余均采用默认设置。
接着,我们就来分步详细阐述。
第一步,增加一个ATLObject到该项目中。
VC菜单Insert->NewATLObject…,在弹出的对话框中选择“InternetExplorerObject”,输入COM类名(在ShortName后输入EyeOnIE,其它各项会自动生成)。
完成后,我们可以看到CEyeOnIE类有一个基类IObjectWithSiteImpl,这个就是实现IObjectWithSite接口的模版类。
第二步,实现IObjectWithSite的接口方法。
在这之前,我们要先定义几个成员变量:
CComQIPtrmWebBrowser2,(需要加入#include"ExDisp.h"),用以保存浏览器组件的指针;DWORDmCookie,用以保存与浏览器的连接ID。
IObjectWithSite有两个接口方法:
SetSite和GetSite。
我们只需重载SetSite就行了。
在EyeOnIE.h中增加函数声明STDMETHOD(SetSite)(IUnknown*pUnkSite),在EyeOnIE.cpp实现如下:
STDMETHODIMPCEyeOnIE:
:
SetSite(IUnknown*pUnkSite)
{
USES_CONVERSION;
if(pUnkSite)
{
mWebBrowser2=pUnkSite;
if(mWebBrowser2)
{
returnRegisterEventHandler(TRUE);
}
}
returnE_FAIL;
}
HRESULTCEyeOnIE:
:
RegisterEventHandler(BOOLinAdvise)
{
CComPtr
//ReceivestheconnectionpointforWebBrowserevents
CComQIPtr
HRESULThr=spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2,&spCP);
if(FAILED(hr))
returnhr;
if(inAdvise)
{
//Passtheeventhandlerstothecontainer
hr=spCP->Advise(reinterpret_cast
}
else
{
spCP->Unadvise(mCookie);
}
returnhr;
}
我们可以看到,SetSite的参数实际上指向的是浏览器组件。
在SetSite实现中,我们首先保存浏览器组件指针,然后将该BHO向浏览器注册为事件处理器。
第三步,实现IDispatch接口方法。
事件处理也就在IDispatch:
:
Invoke中实现(各个事件的ID在ExDispID.h中定义)。
BHO可能会接收到很多事件,但我们只需要响应我们感兴趣的那一部分。
首先在EyeOnIE.h中增加该函数的声明,在EyeOnIE.cpp的实现中,笔者试着响应浏览器浏览一个地址之前发出的事件DISPID_BEFORENAVIGATE2,以此来实现简单的网址过滤功能,代码参考如下:
STDMETHODIMPCEyeOnIE:
:
Invoke(DISPIDdispidMember,REFIIDriid,LCIDlcid,
WORDwFlags,DISPPARAMS*pDispParams,
VARIANT*pvarResult,EXCEPINFO*pexcepinfo,
UINT*puArgErr)
{
USES_CONVERSION;
if(!
pDispParams)
returnE_INVALIDARG;
switch(dispidMember)
{
//
//TheparametersforthisDISPIDareasfollows:
//[0]:
Cancelflag-VT_BYREF|VT_BOOL
//[1]:
HTTPheaders-VT_BYREF|VT_VARIANT
//[2]:
AddressofHTTPPOSTdata-VT_BYREF|VT_VARIANT
//[3]:
Targetframename-VT_BYREF|VT_VARIANT
//[4]:
Optionflags-VT_BYREF|VT_VARIANT
//[5]:
URLtonavigateto-VT_BYREF|VT_VARIANT
//[6]:
Anobjectthatevaluatestothetop-levelorframe
//WebBrowserobjectcorrespondingtotheevent.
//
caseDISPID_BEFORENAVIGATE2:
{
LPOLESTRlpURL=NULL;
mWebBrowser2->get_LocationURL(&lpURL);
char*strurl;
if(pDispParams->cArgs>=5&&pDispParams->rgvarg[5].vt==(VT_BYREF|VT_VARIANT))
{
CComVariantvarURL(*pDispParams->rgvarg[5].pvarVal);
varURL.ChangeType(VT_BSTR);
strurl=OLE2A(varURL.bstrVal);
}
if(strstr(strurl,""))
{
*pDispParams->rgvarg[0].pboolVal=TRUE;
:
:
MessageBox(NULL,_T("该网页已被禁止!
"),_T("Warning"),MB_ICONSTOP);
returnS_OK;
}
break;
}
caseDISPID_NAVIGATECOMPLETE2:
break;
caseDISPID_DOCUMENTCOMPLETE:
break;
caseDISPID_DOWNLOADBEGIN:
break;
caseDISPID_DOWNLOADCOMPLETE:
break;
caseDISPID_NEWWINDOW2:
break;
caseDISPID_QUIT:
RegisterEventHandler(FALSE);
break;
default:
break;
}
returnS_OK;
}
我们看到,当用户浏览的新地址包含""字符的时候,浏览器就会弹出一个警告对话框,并且停止进一步的动作。
另外值得注意的是,在DISPID_QUIT事件(浏览器将要退出)的响应中,我们将BHO事件处理器进行了注销。
第四步,因为BHO可能会被文件浏览器加载。
如果我们不想这样,我们就要在DllMain中对加载者进行判断,参考如下:
extern"C"
BOOLWINAPIDllMain(HINSTANCEhInstance,DWORDdwReason,LPVOID/*lpReserved*/)
{
if(dwReason==DLL_PROCESS_ATTACH)
{
//Checkwho''sloadingus.
//Ifit''sExplorerthen"nothanks"andexit...
TCHARpszLoader[MAX_PATH];
GetModuleFileName(NULL,pszLoader,MAX_PATH);
_tcslwr(pszLoader);
if(_tcsstr(pszLoader,_T("explorer.exe")))
returnFALSE;
_Module.Init(ObjectMap,hInstance,&LIBID_BHOPLUGINLib);
DisableThreadLibraryCalls(hInstance);
}
elseif(dwReason==DLL_PROCESS_DETACH)
_Module.Term();
returnTRUE;//ok
}
最后,别忘了修改注册表文件,追加BHO的注册信息。
在EyeOnIE.rgs文件的下面增加如下代码:
HKLM
{
SOFTWARE
{
Microsoft
{
Windows
{
CurrentVersion
{
Explorer
{
''BrowserHelperObjects''
{
{6E28339B-7A2A-47B6-AEB2-46BA53782379}
}
}
}
}
}
}
}
注意,{6E28339B-7A2A-47B6-AEB2-46BA53782379}是笔者这个BHO的CLSID,如果你自己开发BHO,这里应该正确填写你的CLSID。
好了,一个简单的BHO开发完成了。
(可以到本人的个人主页下载实例源代码。
)BHO插件可以实现的功能还有很多,比如网页内容分析、IE界面定制等等。
作为总结,笔者还要提醒读者一点的是,如果不想让BHO起作用了,可以注销该插件,如下格式:
regsvr32/uyourpath\yourbho.dll,或者直接在注册表中将“BrowserHelperObjects”目录下注册的CLSID删掉。
正文完
如何使用BHO定制你的InternetExplorer浏览器
原文:
微软公司DinoEsposito
编译:
朱先中
原文出处:
BrowserHelperObjects:
TheBrowsertheWayYouWantIt
一、简介
有时,你可能需要一个定制版本的浏览器。
在这种情况下,你可以自由地把一些新颖但又不标准的特征增加到一个浏览器上。
结果,你最终有的只是一个新但不标准的浏览器。
Web浏览器控件只是浏览器的分析引擎。
这意味着仍然存在若干的与用户接口相关的工作等待你做――增加一个地址栏,工具栏,历史记录,状态栏,频道栏和收藏夹等。
如此,要产生一个定制的浏览器,你可以进行两种类型的编程――一种象微软把Web浏览器控件转变成一个功能齐全的浏览器如InternetExplorer;一种是在现有的基础上加一些新的功能。
如果有一个直接的方法定制现有的InternetExplorer该多好?
BHO(BrowserHelperObjects,我译为"浏览器帮助者对象",以下皆简称BHO)正是用来实现此目的的。
二、关于软件定制
以前,定制一个软件的行为主要是通过子类化方法实现的。
通过这种办法,你可以改变一个窗口的外表与行为。
子类化虽然被认为是一种有点暴力方式――受害者根本不知道发生的事情――但它还是长时间以来的唯一的选择。
随着微软Win32API的到来,进程间子类化不再被鼓励使用并愈发变得困难起来。
当然,如果你是勇敢的--指针从未吓倒你,而最重要的是,如果你已经游刃于系统钩子之间,你可能觉得这一问题太简单了。
但是情形并不总是这样。
暂放下这点不管,问题在于每一个进程运行在自己的地址空间中,而且打破进程边界略微有些不正确性。
另一方面,你可能需要对定制进行更好的管理。
更经常情况下,定制可能是程序本身强烈要求实现的。
在后者情况下,已安装的软件只需在既定的磁盘位置查询另外的组件模块,然后装载、设定初值,最后让它们自由地按照既定的设计工作。
这正是InternetExplorer浏览器和它的BHO所要实现的。
三、什么是BHO?
从某种观点看,InternetExplorer同普通的Win32程序没有什么两样。
借助于BHO,你可以写一个进程内COM对象,这个对象在每次启动时都要加载。
这样的对象会在与浏览器相同的上下文中运行,并能对可用的窗口和模块执行任何行动。
例如,一个BHO能够探测到典型的事件,如GoBack、GoForward、DocumentComplete等;另外BHO能够存取浏览器的菜单与工具栏并能做出修改,还能够产生新窗口来显示当前网页的一些额外信息,还能够安装钩子以监控一些消息和动作。
简而言之,BHO的工作如我们打入浏览器领地的一位间谍(注意这是微软允许的合法工作)。
在进一步了解BHO细节之前,有几点我需要进一步阐述。
首先,BHO对象依托于浏览器主窗口。
实际上,这意味着一旦一个浏览器窗口产生,一个新的BHO对象实例就要生成。
任何BHO对象与浏览器实例的生命周期是一致的。
其次,BHO仅存在于InternetExplorer4.0及以后版本中。
如果你在使用MicrosoftWindows?
98,Windows2000,Windows95,orWindowsNT版本4.0操作系统的话,也就一块运行了活动桌面外壳4.71,BHO也被Windows资源管理器所支持。
BHO是一个COM进程内服务,注册于注册表中某一键下。
在启动时,InternetExplorer查询那个键并把该键下的所有对象预以加载。
InternetExplorer浏览器初始化这一对象并要求某一接口功能。
如果发现这一接口,InternetExplorer使用其提供的方法传递IUnknown指针到BHO对象。
见图一:
图一ie浏览器如何装入和初始化BHO对象,BHO场所(site)是用于实现通信的COM接口
浏览器可能在注册表中发现一系列的CLSID,并由此为每个CLSID建立一个进程中实例。
结果是,这些对象被装载至浏览器上下文中并运行起来,好象它们是本地组件一样。
但是,由于InternetExplorer的COM特性,即使被装入到它的进程空间中于事(你的野心实现)也不一定会有多大帮助。
用另一说法,BHO的确能够做许多潜在的有用的事情,如子类化组成窗口或者安装线程局部钩子,但是它确实远离浏览器的核心活动。
为了钩住浏览器的事件或者自动化浏览器,BHO需要建立一个私有的基于COM的通讯通道。
为此,该BHO应该实现一个称为IObjectWithSite的接口。
事实上,通过接口IobjectWithSite,InternetExplorer可以传递它的IUnknown接口。
BHO反过来能够存储该接口并进一步查询更专门的接口,如IWebBrowser2、IDispatch和IConnectionPointContainer。
另外一种分析BHO对象的途径与InternetExplorer外壳扩展有关。
我们知道,一个WINDOWS外壳扩展即是一个进程内的COM服务器,它在Windows资源管理器执行某种动作时装入内存――如显示上下文菜单。
通过建立一个实现几个COM接口的COM模块,你就给上下文菜单加上一些项并能预以正确处理。
一个外壳扩展必须以Windows资源管理器能够发现的方法注册。
一个BHO对象遵循同样的模式――唯一的改变在于要实现的接口。
然而,尽管实现方式有所不同,外壳扩展与BHO仍有许多共同的特点。
如下表一:
表一外壳扩展与BHO相近特性比较
特性
外壳扩展
BHO对象
加载者
Windows资源管理器
InternetExplorer(和外壳4.17及以上版本的Windows资源管理器)
击活动作
在某类文档上的用户动作(即单击右键)
打开浏览器窗口
何时卸载
参考计数达到0的几秒之后
导致它加载的窗口关闭时
实现形式
COM进程中DLL
COM进程中DLL
注册需求
常常是为一个COM服务器设置的入口处,另加的入口依赖于外壳类型及它要应用至的文档类型
常常是为一个COM服务器设置的入口处,另加一个把它申请为BHO的注册入口
接口需求
依赖于外壳扩展的类型
IObjectWithSite
如果你对SHELL扩展编程有兴趣的话,可以参考MSDN有关资料。
四、BHO的生存周期
前面已经说过,BHO不仅仅为InternetExplorer所支持。
如果你在使用外壳4.71或者更高版本,你的BHO对象也会被Windows资源管理器所加载。
下表二展示了我们可以使用的不同版本的外壳产品情况,Windows外壳版本号存于库文件shell32.dll中。
表二不同版本的Windows外壳对于BHO的支持情况
外壳版本
安装的产品
BHO的支持情况
4.00
Windows95,Windows NT4.0带或不带InternetExplorer4.0或更老版本。
注意没有安装外壳更新
InternetExplorer4.0
4.71
Windows95,WindowsNT4.0带InternetExplorer4.0和活动桌面外壳更新
InternetExplorer与Windows资源管理器
4.72
Windows98
InternetExplorer与Windows资源管理器
5.00
Windows2000
InternetExplorer与Windows资源管理器
BHO对象随着浏览器主窗口的显示而装入,随着浏览器主窗口的销毁而缷载。
如果你打开多个浏览器窗口,多个BHO实例也一同产生。
无论浏览器以什么样的命令行启动,BHO对象都被加载。
举例来说,即使你只是想要见到特定的HTML页或一个给定的文件夹,BHO对象也被加载。
一般地,当explorer.exe或iexplore.exe运行的时候,BHO都要被考虑在内。
如果你设置了"Openeachfolderinitsownwindow"(对每一个文件夹以一个独立窗口打开)文件夹选项,那么你每次打开一个文件夹,BHO对象都要被加载。
见图二。
图二经过这样设置,你每次打开一个文件夹时,执行一个独立的explorer.exe实例,并装入已注册的BHO对象。
但是注意,这种情形仅适于当你从桌面上的"我的电脑"图标中打开文件夹的情况。
在这种情况下,每次你移到另外一个文件夹时外壳都要调用explorer.exe。
这种情况在你同时用两个窗格进行浏览时是不会发生的。
事实上,当你改变文件夹时,外壳是不会启动浏览器的新的实例的而仅是简单创建嵌入视图对象的另外一个实例。
奇怪的是,如果你在地址栏中输入一个新的名字来改变文件夹时,在同一个窗口中同样可以达到浏览之目的,无论Windows资源管理器视图是单个的还是双视图形式。
对于InternetExplorer的情形,事情要更简单一些。
只有你显式地多次运行iexplore.exe浏览器时,你才有多个InternetExplorer的拷贝。
当你从InternetExplorer中打开新的窗口时,每一个窗口在一个新的线程中被复制而不是创建一个新的进程,因此也就不需要重新载入BHO对象。
首先,BHO最有趣的地方是,它是极度动态的。
每次Windows资源管理器或者InternetExplorer打开,装载器从注册表中读取已安装的BHO对象的CLSID然后处理它们。
如果你在打开的浏览器多个实例中间编辑注册表的话,你可以随着多个浏览器拷贝的载入而装入多个不同的BHO。
这就是说,如果你选择从头创建一个新的属于自己的浏览器,那么你可以把它内嵌在一个VisualBasic或者MFC框架窗口中。
同时你有相当的机会来灵活安排浏览程序。
如果它们能满足你的需要的话,你可以依赖于InternetExplorer的强大的功能并且加上你想要的尽可能多的插件。
五、关于IObjectWithSite接口
从一个高起点来看,BHO即
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC 开发 BHO 插件 定制 浏览器