為了鉤住瀏覽器事件或自動化它,Browser Helper Object (BHO)需要建立一個專有并基于COM渠道的通信。緣于此,BHO應該實現(xiàn)IObjectWithSite這個接口,以DLL的形式給IE增加特定功能。用IObjectWithSite,IE將傳遞一個指向它的IUnknown接口的指針。于是,BHO能保存并查找更多特定的接口,如IWebBrowser2, IDispatch和IConnectionPointContainer。BHO不僅支持IE而且還會在Windows Explorer中被加載,它的聲明周期跟瀏覽器實例的生命周期一致。IE7為新選項卡創(chuàng)建并銷毀一個新的BHO,BHO不會被支持WebBrowser control的應用程序或者HTML對話框窗口加載。
BHO是動態(tài)的,每次Windows Explorer或Internet Explorer的窗口被打開,加載器從注冊表讀已安裝上的BHO的CLSID并處理它們。COM分為進程內和進程外組件,用動態(tài)鏈接庫實現(xiàn)組件程序時,客戶程序調用組件程序來服務會把組件程序裝入自己的進程中,這樣客戶程序和組件程序運行在同一進程控件中,這種叫作進程內組件;實現(xiàn)組件程序另一種形式是EXE程序,它被調用時自己有進程空間,這樣客戶程序和組件程序運行在不同的進程空間中,這種叫作進程外組件。BHO是一個COM進程內服務器,于是最好的方法是用ATL構建。BHO位于注冊表HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\下。
寫好BHO后,按F5使得程序Debug運行,這時會彈出”Executable For Debug Session”窗口,在”Executable file name”中選擇iexplore.exe。調試時設置斷點后,如果不顯示信息,如果此時系統(tǒng)是Windows Server,需要Disable Internet Explorer Enhanced Security。在SetSite方法上設置斷點,這時你將發(fā)現(xiàn),IE將調用這個方法兩次,一次用來建立連接,另一次則是退出。
ATL智能指針CComQIPtr和CComPtr都能用作管理COM接口指針,都聲明在頭文件atlbase.h中。CComQIPtr包含了CComPtr的所有功能,但CComQIPtr由于使用了運算符重載會自動調用函數(shù)QueryInterface,于是CComQIPtr不能定義IUnknown指針即CComQIPtr<IUnknown>不正確,而應該是CComQIPtr<IUnknown, &IID_IUnknown>。
BSTR是一種OLE自動化類型以傳輸長度在前的數(shù)據(jù),BSTR是一個指向以0值結尾('\0')的指針;_bstr_t類是BSTR數(shù)據(jù)類型的C++封裝;CComBSTR類是BSTR類型的ATL封裝。VARIANT是變量數(shù)據(jù)類型,定義在OAIDL.H自動化頭文件中,適用于引用傳遞參數(shù)類型位置;_variant_t類是VARIANT數(shù)據(jù)類型的C++封裝;CComVariant類是VARIANT類型的ATL封裝。ATL程序中CComBSTR轉換成CString,需要加入頭文件"comutil.h"和<iostream>。
WebBrowser控件能給你的應用程序增加瀏覽、文檔視圖和數(shù)據(jù)下載的能力,使用這一控件的應用程序將使用戶能瀏覽互聯(lián)網上的網頁和本地或網絡文件夾。WebBrowser控件同時支持通過點擊超鏈接和URL導航,這個控件維護了一個歷史別表,它允許用戶前進和后退到以前瀏覽過的站點、文件夾和文檔。WebBrowser控件對應的IE動態(tài)鏈接庫是ShDocVw.dll,對應頭文件和IDL分別為Exdisp.h和Exdisp.Idl。
IE的核心叫Trident渲染引擎也稱為MSHTML,它對應的IE動態(tài)鏈接庫是mshtml.dll。mshtml.dll負責在屏幕上顯示網頁并處理網頁的DOM,mshtml.dll解析HTML/CSS文件并且創(chuàng)建內部的DOM樹來展現(xiàn)它,mshtml.dll也公開了運行時查看和修改DOM樹的API集,mshtml.dll對應頭文件和IDL分別是MsHTML.h和MsHTML.Idl。MSHTML中的接口IHTMLDocument~IHTMLDocument6實現(xiàn)了文檔對象的所有成員。
頭文件ShlGuid.h中定義了IWebBrowser2的接口標識,頭文件ExDispid.h中定義了瀏覽器事件的調度標識符。ATL3.0引入了類IDispEventImpl,IDispEventImpl僅能處理雙接口。事件接收映射被用作建立事件處理,有宏BEGIN_SINK_MAP、SINK_ENTRY/SINK_ENTRY_EX和END_SINK_MAP。為了通過事件映射連接到瀏覽器的事件句柄,需要調用DispEventAdvise;最后調用DispEventUnadvise斷開連接。接口DWebBrowserEvents2取代了已廢棄的接口DWebBrowserEvents。
IE事件DocumentComplete在頁面被下載和解析之后被激發(fā),但在window.onload事件被觸發(fā)之前,也不會響應Refresh操作;即使腳本(<script>)中加入DEFER屬性(它能使頁面完全載入后再執(zhí)行相當于window.onload),該事件也會被執(zhí)行,因為腳本在下載后被加載,但在文檔完成前。當用戶點擊Refresh按鈕時,DownloadBegin和DownloadComplete事件觸發(fā);如果用戶在頁面下載中途點擊Stop按鈕,這會阻止DownloadComplete事件觸發(fā)。DownloadBegin事件表明頁面正在從服務器傳輸,通常它后面對應一個DownloadComplete事件,這兩個事件成對發(fā)生直到該頁面和所有它的frame被下載,然后發(fā)生事件DocumentComplete。當用戶點擊Refresh按鈕但文檔沒改變,DownloadComplete事件單獨發(fā)生,此時其后不會發(fā)生事件DocumentComplete。如果一個頁面已完成下載,top-level瀏覽器最后觸發(fā)事件DocumentComplete,見KB 180366。
【資源】
Browser Helper Objects: The Browser the Way You Want It
SAMPLE: IEHelper-Attaching to Internet Explorer 4.0 by Using a Browser Helper Object