在Windows操作系统上,我们最常见的浏览器有两种:文件浏览器(exploer.exe,应用于文件系统)和Internet浏览器(iexplore.exe,应用于互联网资源)。由于这两个浏览器功能强大,而且又与Windows操作系统捆绑销售,最终也就成为了浏览器的标准。但有时候,为了给浏览器加入一些新的特性,我们往往会重新设计一个自己的浏览器。新的浏览器模仿标准浏览器的大部分功能,同时加入新特性。这种做法最直观,但实际上也是相对于微软的重复劳动,且工作量比较大。其实,使用BHO插件,一切都变得很简单。
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实例只有在创建它的浏览器窗口销毁时才被释放。)下图演示了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和文件浏览器 |
| STDMETHODIMP CEyeOnIE::SetSite(IUnknown *pUnkSite) { USES_CONVERSION; if (pUnkSite) { mWebBrowser2 = pUnkSite; if (mWebBrowser2) { return RegisterEventHandler(TRUE); } } return E_FAIL; } HRESULT CEyeOnIE::RegisterEventHandler(BOOL inAdvise) { CComPtr<IConnectionPoint> spCP; // Receives the connection point for WebBrowser events CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> spCPC(mWebBrowser2); HRESULT hr = spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP); if (FAILED(hr)) return hr; if (inAdvise) { // Pass the event handlers to the container hr = spCP->Advise(reinterpret_cast<IDispatch*>(this), &mCookie); } else { spCP->Unadvise(mCookie); } return hr; } |
我们可以看到,SetSite的参数实际上指向的是浏览器组件。在SetSite实现中,我们首先保存浏览器组件指针,然后将该BHO向浏览器注册为事件处理器。
第三步,实现IDispatch接口方法。事件处理也就在IDispatch::Invoke中实现(各个事件的ID在ExDispID.h中定义)。BHO可能会接收到很多事件,但我们只需要响应我们感兴趣的那一部分。首先在EyeOnIE.h中增加该函数的声明,在EyeOnIE.cpp的实现中,笔者试着响应浏览器浏览一个地址之前发出的事件DISPID_BEFORENAVIGATE2,以此来实现简单的网址过滤功能,代码参考如下:
| STDMETHODIMP CEyeOnIE::Invoke(DISPID dispidMember,REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pvarResult,EXCEPINFO * pexcepinfo, UINT * puArgErr) { USES_CONVERSION; if (!pDispParams) return E_INVALIDARG; switch (dispidMember) { // // The parameters for this DISPID are as follows: // [0]: Cancel flag - VT_BYREF|VT_BOOL // [1]: HTTP headers - VT_BYREF|VT_VARIANT // [2]: Address of HTTP POST data - VT_BYREF|VT_VARIANT // [3]: Target frame name - VT_BYREF|VT_VARIANT // [4]: Option flags - VT_BYREF|VT_VARIANT // [5]: URL to navigate to - VT_BYREF|VT_VARIANT // [6]: An object that evaluates to the top-level or frame // WebBrowser object corresponding to the event. // case DISPID_BEFORENAVIGATE2: { LPOLESTR lpURL = NULL; mWebBrowser2->get_LocationURL(&lpURL); char * strurl; if (pDispParams->cArgs >= 5 && pDispParams->rgvarg[5].vt == (VT_BYREF|VT_VARIANT)) { CComVariant varURL(*pDispParams->rgvarg[5].pvarVal); varURL.ChangeType(VT_BSTR); strurl = OLE2A(varURL.bstrVal); } if (strstr(strurl, "girl.com")) { *pDispParams->rgvarg[0].pboolVal = TRUE; ::MessageBox(NULL, _T("该网页已被禁止!"),_T("Warning"),MB_ICONSTOP); return S_OK; } break; } case DISPID_NAVIGATECOMPLETE2: break; case DISPID_DOCUMENTCOMPLETE: break; case DISPID_DOWNLOADBEGIN: break; case DISPID_DOWNLOADCOMPLETE: break; case DISPID_NEWWINDOW2: break; case DISPID_QUIT: RegisterEventHandler(FALSE); break; default: break; } return S_OK; } |
| extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH) { // Check who's loading us. // If it's Explorer then "no thanks" and exit... TCHAR pszLoader[MAX_PATH]; GetModuleFileName(NULL, pszLoader, MAX_PATH); _tcslwr(pszLoader); if (_tcsstr(pszLoader, _T("explorer.exe"))) return FALSE; _Module.Init(ObjectMap, hInstance, &LIBID_BHOPLUGINLib); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok } |
| HKLM { SOFTWARE { Microsoft { Windows { CurrentVersion { Explorer { 'Browser Helper Objects' { {6E28339B-7A2A-47B6-AEB2-46BA53782379} } } } } } } } |

一沙一世界 一花一天堂 掌中握無……

网络编程技术、多媒体技术、PC应用技术
