IE里的探索之定制瀏覽器好助手 (作者:青蘋果工作室編譯 2001年02月08日 14:00)
有些情況下你需要特制的、或多或少有些改變的瀏覽器。這種情況下,你有時候會基于 WebBrowser 控件開發(fā)一個完全定制的模塊,實現(xiàn)按鈕、標題以及用戶界面需要的其它東西。這時,你可以自由地在這個瀏覽器中添加任何新的、非標準的功能。WebBrowser 控件只是瀏覽器的語法分析引擎。這就是說還有很多用戶界面相關(guān)的任務(wù)必須由你完成:添加地址欄、工具條、歷史、狀態(tài)欄、頻道和收藏夾等等。所以,要創(chuàng)建定制的瀏覽器,你必須編寫兩種代碼:將 WebBrowser 控件變成類似于 Microsoft Internet Explorer 的全功能瀏覽器的代碼和支持你的新功能的代碼。如果有一種定制 Internet Explorer 的直接方式不是很好嗎?瀏覽器助手對象 (BHO) 就是做這件事用的。
程序定制 歷史上,定制程序行為的第一種方法是子類。通過這種方法,你能改變程序中給定的窗口處理消息的方式以獲得不同的行為。這是一種原始的實現(xiàn)方式,然而因為受害者很少意識到,在很長一段時間內(nèi)這是唯一的選擇。
Microsoft Win32 API 出現(xiàn)時,不鼓勵使用進程間的子類,而且它們的代碼比較難寫。然而,如果你有一顆勇敢的心,指針從來就嚇不倒你;畢竟,你生活在系統(tǒng)掛鉤的環(huán)境里,你也許會發(fā)現(xiàn)它其實很簡單。但不總是這種情況。不管是多么聰明的編程,有一個問題就是每一個 Win32 進程運行在它自己的地址空間內(nèi),而有時打破這種進程的邊界是不正確的。另一方面,這要求你傾盡全力完成這種編程。更為常見的是,定制可能是指程序本身在設(shè)計時就確定的指定功能。
后來,程序在眾所周知的、預(yù)先指定的磁盤空間尋找附加模塊,加載、初始化它們,然后讓它們完成預(yù)先設(shè)計的工作。這就是 Internet Explorer 和它的助手對象的實際工作方式。
瀏覽器助手對象(BHO)是什么 從這個角度來看,Internet Explorer 就和任何其它使用自己內(nèi)存空間的 Win32 程序一樣。你能使用瀏覽器助手對象編寫組件——進程內(nèi)的組件對象模型 (COM) 組件——Internet Explorer 在每次啟動時加載這些組件。這些組件和瀏覽器運行在相同的內(nèi)存上下文里并且能在可用的窗口和模塊里完成任何操作。例如,一個 BHO 能檢測到瀏覽器的典型事件,如 GoBack、GoForward 和 DocumentComplete;訪問瀏覽器的菜單和工具條并改變它們;創(chuàng)建窗口以顯示當前可視頁面上的附加信息;安裝掛鉤以監(jiān)視消息和操作。簡單地說,BHO 就像我們派出的潛入瀏覽器的間諜一樣工作。
在我們深入到 BHO 核心細節(jié)之前,有些情況我需要說明。首先,BHO 連接在瀏覽器的主窗口上。實際上,這意味著每創(chuàng)建一個瀏覽器窗口,就創(chuàng)建了該對象的一個新實例。任何 BHO 實例同瀏覽器實例同時產(chǎn)生、同時消亡。其次,BHO 只存在于 Internet Explorer 4.0 以上版本。
如你運行帶有 Active Desktop Shell Update (shell 版本 4.71) 的 Microsoft Windows 98、Windows 2000、Windows 95 或者 Windows NT 4.0 版操作系統(tǒng),Windows Explorer 也支持 BHO。以后在討論性能問題和實現(xiàn)壓縮的 BHO 時我們會談到相關(guān)內(nèi)容。
最簡單的情況下,BHO 是一個在特定注冊表項下注冊的進程內(nèi) COM 服務(wù)器。啟動時,Internet Explorer 查找注冊表并加載所有將其 CLSID 保存在此處的對象。瀏覽器初始化對象并要求它提供特定接口。如果發(fā)現(xiàn)了這樣的接口,Internet Explorer 使用所提供的方法將它的 IUnknown 指針傳遞給助手對象。圖1說明了這一過程。
圖 1:Internet Explorer 如何加載并初始化瀏覽器助手對象。BHO site 是建立通訊所用的 COM 接口。
瀏覽器可能在注冊表里發(fā)現(xiàn)一系列 CLSID,并為每一個 CLSID 創(chuàng)建一個進程內(nèi)的實例。結(jié)果,這些對象被加載到瀏覽器的上下文,并且可以向內(nèi)置部件一樣使用。然而,由于瀏覽器本質(zhì)上是基于 COM 的,加載到進程內(nèi)部并不很重要。從另外一方面看,BHO 確實能實現(xiàn)一系列潛在的功能,比如說實現(xiàn)窗口的子類或安裝線程局域掛鉤,但 BHO 的主要目的是脫離瀏覽器核心操作。為了連接瀏覽器事件,或者說,將事件自動化,助手對象需要建立一個有權(quán)限的并且是基于 COM 的通訊通道。所以,BHO 應(yīng)實現(xiàn)名為 IObjectWithSite 的接口。實際上, Internet Explorer 通過 IObjectWithSite 傳遞一個指向它自己的 IUnknown 接口指針。隨后,BHO 就將這個指針保存起來,并通過它獲得其它所需的接口,如 IWebBrowser2、IDispatch 和 IConnectionPointContainer。
可以從另一個方面,即 Internet Explorer 外殼擴展程序的角度來看待 BHO。像你知道的那樣,Windows 外殼擴展程序是一個運行中的com,Windows Explorer裝載后對文檔進行特定操作。例如,顯示它的上下文相關(guān)菜單時,加載的進程 內(nèi)的 COM 服務(wù)程序。通過編寫實現(xiàn)幾個 COM 接口的 COM 模塊,你就能在上下文 相關(guān)菜單中添加菜單項并適當?shù)靥幚硭鼈儭M鈿U展程序必須以 Windows Explorer 能夠找到的方式進行注冊。瀏覽器助手對象遵從同樣的模式 ;唯一的改變是要實現(xiàn)的接口。導致 BHO 被加載的觸發(fā)條件是一個小差別。然而,除了實現(xiàn)的不同之外,像下表所說的那樣,外殼擴展和 BHO 在本質(zhì)上是一樣的。
表 1. 外殼擴展程序和瀏覽器助手對象如何實現(xiàn)一般功能
如果你對外殼擴展程序感興趣,請先參閱 MSDN 在線文檔或 CD 文檔。
助手對象的生命周期 像我們前面提到的那樣,只有 Internet Explorer 支持 BHO。如果你運行了不低于版本 4.71 的外殼,你的 BHO 也可以被 Windows Explorer 載入。這樣可以通過一個單一的瀏覽器并基于同樣的用戶經(jīng)驗同時瀏覽 Web 和本地磁盤。下表提供對當前可用的各種外殼版本的一個面向產(chǎn)品的概覽。外殼的版本號取決于保存在 shell32.dll 中的版本信息。
表 2. 不同外殼版本對瀏覽器助手對象的支持
瀏覽器助手對象在瀏覽器的主窗口將要顯示出來時加載,在窗口消失時卸載。你打開的瀏覽器窗口越多,創(chuàng)建的 BHO 實例也就越多。即使以命令行方式啟動瀏覽器它也被加載。一般情況下,BHO 實例的數(shù)目和運行的 explorer.exe 或 iexplorer.exe 的數(shù)目一樣多。如果你在文件夾選項里設(shè)置了“在不同窗口打開不同文件夾”,每次你打開一個新的文件夾時都會加載 BHO。
圖 2. 使用這一設(shè)置,每打開一個文件夾就運行 explorer.exe 的一個單獨實例 并加載注冊了的 BHO。
然而,需要注意的是,這種情況僅僅發(fā)生在你從桌面上“我的電腦”圖標開始打開文件夾的時候。在這種情況下,每次你轉(zhuǎn)移到另外的文件夾時外殼都調(diào)用 explorer.exe。你在兩欄視圖中開始瀏覽時不會發(fā)生這種情況。實際上,你改變文件夾時外殼并不是啟動瀏覽器的一個新實例,而是簡單的創(chuàng)建嵌入視圖對象的一個實例。特別是你在地址欄里輸入一個新名字以改變文件夾時,無論 Windows Explorer 的視圖是一欄還是兩欄,瀏覽都在同一窗口內(nèi)進行。
對 Internet Explorer 來說情況就簡單多了。只有你多次顯式地運行 iexplorer.exe 才會產(chǎn)生多個拷貝。當你從 Internet Explorer 中打開新窗口時,每個窗口在一個新的線程中復制,而不是創(chuàng)建一個新的進程,這樣就不會重新加載 BHO。
尤其,BHO 最令人感興趣的特征就是它們是動態(tài)的。每次打開 Window Explorer 或 Internet Explorer 的窗口時,它們從注冊表里讀取已安裝的助手對象的 CLSID,然后進行處理。如果你編輯打開瀏覽器的不同實例的注冊表項,就能使瀏覽器的不同拷貝加載不同的 BHO。這意味著你有了一個非常好的選擇以取代編寫新的瀏覽器。你可以在 Microsoft Visual Basic 或 Microsoft Foundation Classes (MFC) 的 frame window 中嵌入 WebBrowser。同時,你有很好的機會布置擴展性很強的瀏覽應(yīng)用程序。你可以依賴Internet Explorer的全部功能并盡可能地添加想要的附加功能以滿足你的需要。
|