BHO(Browser Helper Object,瀏覽器輔助對象,簡稱BHO)。BHO是微軟推出的作為瀏覽器對第三方程序員開放交互接口的業(yè)界標(biāo)準(zhǔn),通過簡單的代碼就可以進(jìn)入瀏覽器領(lǐng)域的“交互接口”(INTERACTIVED Interface)。通過這個接口,程序員可以編寫代碼獲取瀏覽器的行為,比如“后退”、“前進(jìn)”、“當(dāng)前頁面”等,利用BHO的交互特性,程序員還可以用代碼控制瀏覽器行為,比如修改替換瀏覽器工具欄,添加自己的程序按鈕等。這些在系統(tǒng)看來都是沒有問題的。BHO原來的目的是為了更好的幫助程序員打造個性化瀏覽器,以及為程序提供更簡潔的交互功能,現(xiàn)在很多IE個性化工具就是利用BHO的來實(shí)現(xiàn)。
在正式利用VC++編寫代碼之前,我們需要了解一些東西,首先是IE瀏覽器加載BHO插件的原理。
1.IE的窗口打開時,先尋找HKLM下的SOFTWA RE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\里的CLSID,這些CLSID,都對應(yīng)著相應(yīng)的BHO插件,然后根據(jù)這個CLSID到HKCR下的CLSIDs里找到此插件的信息,包括文件位置等。
2.IE根據(jù)找到的CLSID信息創(chuàng)建BHO對象,并且查找IObjectWithSite接口。(這個接口非常簡單,只有SetSite和GetSite兩個方法)
3.IE把IWebBrowser2(瀏覽器插件)傳到BHO的SetSite方法,用戶在此方法中可掛載自己的事件處理方法。
4.窗口關(guān)閉時,iE把null傳到BHO的SetSite方法,此方法用來去掉掛載的事件處理方法。
了解了IE瀏覽器加載BHO的方法之后,我們就來看一下BHO插件的編寫流程。
1、創(chuàng)建IObj ectWithSite顯式接口,創(chuàng)建COM類型,實(shí)現(xiàn)繼承IObjectWithSite接口
2、實(shí)現(xiàn)此接口并在SetSite方法里加上所要掛載的事件
3、處理事件
4、注冊此BHO到注冊表中HKLM下的Softw are\\Microsoft\\Windows\\CurrentVersion\\ExplorerBrowser Helper Objects;(HKCR下的CLSIDs是根據(jù)上面的路徑自動注冊的)
5、.net下須設(shè)置此BHO項(xiàng)目的”配置屬性一>生成”中為Interop注冊為True,這樣才能將.net類庫文件注冊到COM。
我們采用VC6.O創(chuàng)建好環(huán)境之后,就要進(jìn)行代碼的編寫了。由于我們在IE瀏覽器中加載插件,所以其他的瀏覽器我們就不允許dll加載了。這樣我們就需要在dllMain函數(shù)中對加載該dll的程序進(jìn)行判斷,代碼如下:
STDMETHODIMP CIEH1probj::lnvoke(DISPID dispidMemberm,REFIID riid,LCID lcid,WORD wFlags,
DISPPARAMS*pDispParams,VARIANT*pvarResult,
EXCEPINFO* pExceplnfo,UINT*puArgerr)
{
USES_CONVERSION;
if (!pDispParams)
return E_INVALIDARG;
LPOLESTR lpURL=NULL;
m_spwebBrowser2->get_LocationURL(&lpURL);
char sitelist{100}{1024}; //所有站點(diǎn)名稱(1024)
char site{1024}; //站點(diǎn)名稱
ifstream in("C:\\SiteList dat",ios::in);//從我們的文件中讀取要檢測的網(wǎng)址
if(in.fail())
{
return E_INVALIDARG;
}
這段代碼我們添加在dllMain函數(shù)的開始位置,這樣就能確保只有iexplore.exe才能加載我們的插件。BHO對象與瀏覽器進(jìn)行交互是通過事件實(shí)現(xiàn)的,那么他們之間的交互有幾種事件呢?下面就列舉一下常用到的事件:
DISPID__ BEFORENAVIGATE2: 該事件在瀏覽器準(zhǔn)備下載網(wǎng)頁之前觸發(fā),這樣這個事件就可以用在我們檢測用戶輸入的網(wǎng)頁地址上。
DISPID_DOWNLOADBEGrN:該事件在瀏覽器開始下載網(wǎng)頁時觸發(fā)。
DISPID_NAVIGATECOMPLETE:該事件是在一個鏈接(網(wǎng)頁窗口或者網(wǎng)頁Frame框架窗口)被完全打開后,IE瀏覽器或WebBrowser控件觸發(fā)的事件。這個事件已經(jīng)廢棄。應(yīng)該使用DISPIDNAVIGATECOMPLETE2。
DISPID_DOVVrNLOADCOMPLETE:該事件在網(wǎng)頁完全被瀏覽器下載完畢之后觸發(fā)。
DISPID_DOCUMENTCOMPLETE:頁面加載完畢時觸發(fā)該事件,當(dāng)每個FRAME加載完畢后都會觸發(fā)DISPID_DOCUMENTCOMPLETE。可以在DISPID_DOCUMENTCOMPLETE中,判斷是否是整個頁面加載完畢。
DISPID_NEWWINDOW2:該事件在有新的窗口打開時觸發(fā),例如彈窗網(wǎng)頁。
了解了上述的事件機(jī)制之后,我們就明確怎么編寫我們的代碼了,既然是監(jiān)控網(wǎng)址的,那么我們可以在DISPID_BEFORENAVIGATE2事件中對網(wǎng)址進(jìn)行監(jiān)控。事件的方法我們需要在Invoke函數(shù)中編寫。這里我們用switch語句對事件進(jìn)行判斷,要處理的網(wǎng)址我們放到文件里,讓程序從文件里讀取網(wǎng)址,然后與用戶輸入的網(wǎng)址進(jìn)行對比。
編譯之后生成了一個dll文件,這就是我們需要的文件。我們在網(wǎng)址文件中寫入我們需要攔截的網(wǎng)址,這里用百度做測試。下一步就是注冊我們的dll文件,用cmd命令“regsvr32 c://IEHelper.dll”來注冊,注冊結(jié)果,注冊成功。我們打開一個新的網(wǎng)頁,輸入網(wǎng)址百度回車,彈出了我們的顯示信息,ok,到這里我們的目的就完成了,當(dāng)然讀者可以通過修改上述代碼進(jìn)行二次開發(fā),可以實(shí)現(xiàn)網(wǎng)址替換、網(wǎng)頁內(nèi)容替換等等功能,這些有待讀者自己挖掘。