目录
一,BHO开发概述
1.1 BHO的用途及实际应用
1.2 BHO的工作原理及技术环境
二,框架设计
2.1 构建BHO框架
2.2实现IObjectWithSite的接口方法
三,注销Session
3.1将BHO注册为浏览器的事件处理器
3.2监听浏览器关闭事件,并向Server发送跳转指令
3.3关闭BHO注销页面
3.4阻止文件浏览器加载BHO
3.5向注册表中注册BHO组件
四,打包发布
4.1 BHO打包和找到关联Dll文件
4.2编写自动安装脚本inf文件
4.3用cabarc工具打包。
BHO(Browser Help Objects),是实现了特定接口的COM组件。BHO只适用于Windows系统下的IE浏览器和文件浏览器。开发好的BHO插件在注册表特定的位置注册好后,每当微软的浏览器启动,BHO实例就会被创建。在浏览器工作的过程中,BHO会接收到很多事件,比如浏览器浏览新的地址、前进或后退、生成新的窗口、浏览器退出等等。BHO可以在这些事件的响应中实现与浏览器的交互。
本文档中我们将通过编写一个BHO实例来详细讲解BHO开发的一般流程。该实例的功能是:当用户成功登陆网站后,如果用户点击IE关闭按钮,BHO将捕获IE关闭事件,同时向Server发送一个注销当前用户Session的请求。Server注销后跳转到BHO注销页面,BHO捕获到BHO注销页面时,关闭该页面。
BHO是COM组件,而且一定实现了IObjectWithSite接口。这些组件除了在注册表中注册为COM Server外,还必须将它们的CLSID在HKEY_LOCAL_MACHINE/SOFTWARE/ Windows/ CurrentVersion/ Explorer/Browser Helper Objects下注册为子键。微软在设计浏览器的时候,已经给这些组件预留了空间。每当浏览器启动时,浏览器会首先在上述注册表位置查看是否有注册的 BHO CLSID;如果有则分别创建一个实例,并对BHO实例进行初始化,建立交互连接。(注:BHO实例只有在创建它的浏览器窗口销毁时才被释放。)图1.1演示了BHO的创建过程:
图1.1
表1.1 BHO支持的操作系统一览及IE一览
IE版本 |
操作系统版本 |
支持BHO |
4.00 |
Windows 95 and Windows NT 4.0 |
仅IE4.0 |
5.00 |
Windows2000 |
IE和文件浏览器 |
6.00 |
WindowsXP |
IE和文件浏览器 |
7.00 |
Vista |
IE和文件浏览器 |
n 开发环境: Microsoft Visual C++ 6.0
n 步骤1:建立一个工作区(WorkSpace)。
n 步骤2:在工作区中,建立一个 ATL 工程(Project)。示例程序叫TEST,并选择DLL方式,见图2.1。
图2.1
n 步骤3:增加ATL对象类。在菜单 Insert/New ATL Object...(或者用鼠标右键在 ClassView 卡片中弹出菜单)并选择Object 分类,选中 Internet Exploer 项目。见图2.2。
图2.2
n 步骤4:填写COM类的名称。只要输入Short Name,其它自动生成。见图2.3。
图2.3
n 步骤1:先定义几个成员变量:CComQIPtr
变量声明 |
图2.4(详见MyBho.h文件)
n 步骤2:IObjectWithSite有两个接口方法:SetSite和GetSite。我们只需重载 SetSite就行了。在ImyBho中增加函数声明SetSite函数。见图2.5
图2.5
n 步骤3: 实现IDispatch接口方法。事件处理也就在IDispatch::Invoke中实现(各个事件的ID在ExDispID.h中定义)。 BHO可能会接收到很多事件,但我们只需要响应我们感兴趣的那一部分。首先在ImyBho中增加该函数的声明。见图2.6
图2.6
n 步骤4: ImyBho添加RegisterEventHandler(BOOL inAdvise)方法声明,实现向IE注册和注销事件。详见附录代码。
通过上面的步骤,一个基本的BHO对象框架已经建立起来了。下一节来我们将根据具体要实现的功能(向Server发送注销Session命令)对代码主要功能作说明。
注册BHO的事件的工作主要在SetSite函数中来完成。首先保存浏览器指针到mWebBrowser2成员变量中去。然后调用RegisterEventHandler函数向浏览器注册为事件处理器。见图3.1
/************************************************************ 说明:SetSite(IUnknown *pUnkSite)是IObjectWithSite接口的方法。 功能:1.保存浏览器组件指针, 2.BHO向浏览器注册为事件处理器。 ************************************************************/ STDMETHODIMP CMyBho::SetSite(IUnknown *pUnkSite){ if (pUnkSite){ //保存浏览器指针到mWebBrowser2成员变量中去。 mWebBrowser2 = pUnkSite; if (mWebBrowser2){ //向浏览器注册为事件处理器。 return RegisterEventHandler(TRUE); } } return E_FAIL;} } |
/********************************************************** 说明:自定义函数,用以注册/注销BHO事件。 功能:根据传入的参数TRUE/FALSE来向浏览器注册/注销BHO事件。 **********************************************************/ STDMETHODIMP CMyBho::RegisterEventHandler(BOOL inAdvise) { CComPtr // 得到浏览器的连接点 CComQIPtr HRESULT hr = spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP); if (FAILED(hr)){ return hr; } if (inAdvise){ // 向浏览器注册事件。 hr = spCP->Advise(reinterpret_cast }else{ // 向浏览器注销事件。 spCP->Unadvise(mCookie); } return hr; } |
图3.1(详见MyBho.cpp文件)
监听浏览器事件,全部在Invoke函数中来完成。当捕获了浏览器退出事件(DISPID_ONQUIT)时,首先取得页面的窗口名,判读是不是成功登陆页面。如果是,向Server 的LogOffAction发送一组数据,通知Server是BHO注销事件。然后退出IE。见图3.2
case DISPID_ONQUIT: { //取得当前页面的标题。 BSTR lpHader = NULL; mWebBrowser2->get_LocationName(&lpHader); //如果是标题是“登录成功页面”的话,说明用户关闭的是已经登录的主页。 if (strstr( "登录成功页面", OLE2CA(lpHader))){ //需要跳转到Server的LogOutAction中去的URL。 LPTSTR hostUrl = _T("http://localhost:8080/LogOff/logout.do"); //向Server发送"action=BhoLogoff",提示是BHO注销事件。 LPTSTR postData = _T("action=BhoLogoff"); |
//取得POST数据长度。 int size = WideCharToMultiByte(CP_ACP, 0, A2COLE(postData), -1, 0, 0, 0, 0); //为调用Navigate2方法定义参数。 VARIANT vURL; VARIANT vFlags; VARIANT vPostData; VARIANT vHeaders; VARIANT vNull; //此处略去给参数赋值的代码,详见MyBho.cpp中的Invoke函数。 ……………………………………………….. //跳转函数,并向Server发送数据。 mWebBrowser2->Navigate2(&vURL, &vFlags, &vNull, &vPostData, &vHeaders); } //注销BHO事件处理器。 RegisterEventHandler(FALSE); break; } |
图3.2(详见MyBho.cpp文件)
当Server监听到BHO发来的注销命令时,Server注销当前用户的Session后,跳转到一个专门的BHO注销页面(正常情况下是注销退出到登陆页面)。当BHO检测到IE已经跳转到BHO注销页面时,就将窗口关闭。从而使用户对于注销过程可以忽视。见图3.3。
case DISPID_NAVIGATECOMPLETE2://监听页面跳转完毕事件 {//参数合法性检查 if (pDispParams->rgvarg[0].vt == (VT_BYREF|VT_VARIANT)){ char * strurl; CComVariant varURL(*pDispParams->rgvarg[0].pvarVal); varURL.ChangeType(VT_BSTR); strurl = OLE2A(varURL.bstrVal); //如果发现当前的URL是BHO注销页面,则关闭当前页面 if (strstr("http://localhost:8080/LogOff/BhoLogOut.jsp", strurl)){ mWebBrowser2->Quit(); } } break; } |
图3.3(详见MyBho.cpp文件)
为了阻止文件浏览器加载BHO,在Dll入口函数DllMain中加入了判断。见图3.4
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH){ TCHAR pszLoader[MAX_PATH]; GetModuleFileName(NULL, pszLoader, MAX_PATH); _tcslwr(pszLoader); //检查是谁在载入,如果是文件浏览器,则退出。 if (_tcsstr(pszLoader, _T("explorer.exe"))) { return FALSE; } _Module.Init(ObjectMap, hInstance, &LIBID_TESTLib); DisableThreadLibraryCalls(hInstance); }else if (dwReason == DLL_PROCESS_DETACH){ _Module.Term(); } return TRUE; // ok } |
图3.4(详见TEST.cpp文件)
为了向注册表中注册BHO组件,还需要在MyBho.rgs中加入下面的代码。见图3.5
HKLM{ SOFTWARE{ Microsoft{ Windows{ CurrentVersion{ Explorer{ 'Browser Helper Objects'{ {E5155767-23E5-4142-A63B-4DA81B196C36}} } } } } } }
|
图3.5(详见MyBho.rgs文件)
到此,一个简单的注销Seesion的BHO插件开发完毕了,当然还要在根据具体情况,在Server端加以判断才行。详细代码,请参考附录。
经过前面的工作,这个BHO可以打包成CAB格式发布到网站了。当然还要在CAB包中编写一个自动安装的脚步。当用户登录网站,就可以自动安装插件了。下面是详细步骤。
首先,把BHO打包成Dll文件。在VC的Build菜单中选择 Set Active Project Configuration选项,然后再选中Win32 Release MinDependency选项,点击OK。如果此时编译发布出现error LNK2001 错误的话,请到Project->Settings->C/C++中去除_ATL_MIN_CRT这个预处理符号。好了,如果一切顺利的话。我们编译的Dll文件就存放到了我们的工程下的ReleaseMinDependency目录中了。
接下来,由于我们的Dll用到了一些VC自带的Dll库文件。而用户不一定有这些库文件,所有要找到到底用了哪些库文件。这里我们使用VC自带的工具Dependency。(../Microsoft Visual Studio/Common/Tools目录下)。使用它打开我们刚编译好的Dll文件,就可以看到和它关联的所有Dll文件。见图4.1
图4.1
从图中可以看到,当前的Dll用到的VC库文件是OLE32.DLL ,OLEAUT32.DLL。然后我们在Windows/System32目录下找到这两个个文件,复制。然后和生成的test.dll放到一个文件夹。
由于我们的CAB包要自动下载安装到用户的电脑上面,所有必须要编写一个inf安装脚本。关于inf自动安装脚本的说明,详见图4.2
固定格式 |
此处声明都有哪些文件。注意顺序,被调用的dll要放到前面。 |
1. file值告诉ie到哪里去得到这个dll 2. 第二部分告诉声明支持的OS 3. 第三部分是CPU类型 4. thiscab说明在当前的cab文件
|
Dll的CLSID。在VC中的rgs文件中可以找到。 |
是否需要注册 |
dll将要存到本地硬盘的位置,如果它的值是10,则将dll放到/Windows或者/WinNT下;如果是11,则放到/Windows/System或者 /WinNT/System32下;如果是空(就是没有值)则会放到/Windows或者/WinNT下的Downloaded Program Files目录下; |
图4.2
下载此工具http://mydown.yesky.com/yule/meinv/179/418679.shtml
把刚才的文件都拷贝到该工具的BIN目录下面。执行如下命令: cabarc –s 6144 N TEST.CAB oleaut32.dll ole32.dll test.dll TEST.inf 。执行完毕后,会在此目录下生成一个TEST.CAB包。这个压缩包就可以发布到网站了。当然现在这个包没有经过任何签名,在IE的默认安全策略下面是执行不了的,解决办法是:1.把放包的网站设置为信任站点。 2.花钱买一个证书,一年费用好像是5000多。当然我们是测试,所有采用第一种方式。
编写一个HTML文件,插入以下代码:<OBJECT ID="BhoTest" CLASSID="CLSID: E5155767-23E5-4142-A63B-4DA81B196C36" CODEBASE="TEST.CAB">OBJECT> 然后把TEST.CAB放到网站目录下。运行见图4.3
图4.3
由于没有获取认证,所以弹出警告框。点击安装后,我们的文件就被复制到了Windows/Systeme32的目录下面了。并且已经注册。再重启IE,我们的BHO就开始运行了。
注:如需要删除BHO。请用 regsvr32 –u “文件路径 + 文件名”来注销。然后就可以删除掉了。