UMPLatForm.NET 中MiNiWeb瀏覽器核心技術詳解一
目錄
1、 簡介2、 目標、挑戰和解決方案
l 捕捉腳本錯誤
l 過濾彈出窗口
l 添加多標籤頁或多窗口瀏覽功能
l 當一個窗口是由腳本關閉時,需要確認
3、 創建webbrowser擴展控件
l 實現 iwebbrowser2接口
l 實現 dwebbrowserevents2接口
4、 使用該擴展控件
l 捕捉腳本錯誤
l 過濾彈出窗口並添加多標籤頁或多窗口瀏覽功能
l 使用退出事件
平臺內置MiNiWeb瀏覽器如下圖所示:
1、簡介
在.net 2.0的system.windows.forms命名空間中新增了webbrowser控件,該控件本身是非常有用的,但是它沒有提供在某些情況下需要的事件。這篇文章描述瞭如何擴展webbrowser控件並增加一些功能,例如:屏蔽彈出窗口、捕捉腳本錯誤以及捕捉新窗口並將其顯示在多標籤瀏覽窗口環境中。
在擴展webbrowser控件時,某些功能沒有寫入.net framework的幫助文件,不用理會“這個方法是用於支持.net基礎架構的,不推薦直接用於您的代碼中”的提示信息,我們可以創建一個實現iwebbrowser2接口的對象,並使用瀏覽器對象的全部功能,此外,使用dwebbrowserevents2接口可以向控件中添加事件。
我們假設你已經瞭解了iwebbrowser2接口和dwebbrowserevents2接口,對com的互操作和相關的接口知識也是需要了解的。
2、目標、挑戰和解決方案
這個組件要實現的目標是:
l 用簡潔的方式捕捉腳本錯誤
l 過濾彈出窗口
l 加入多標籤頁瀏覽或多窗口瀏覽功能
l 當窗口被腳本關閉時需要確認
這一節簡要講解實現這些目標所碰到的問題和相關的解決方案,下一節中會給出更多的代碼細節。
捕捉腳本錯誤
webbrowser控件有一個scripterrorsuppressed屬性,將這個屬性設置爲true時,該控件確實會比原來多做了一點事情,它不僅禁用了腳本出錯的對話框,而且還禁用了登陸到需要用戶證書的安全站點時出現的登陸對話框。但是假如我們仍然需要這個功能,或者我們想獲得腳本出錯的通知,或者我們想知道全部的腳本出錯的細節時該怎麼辦呢?
腳本錯誤可以在htmlwindow.error事件中捕捉,這個事件會在腳本發生錯誤時觸發幷包含全部的錯誤細節信息,但是難點在於htmlwindow是需要通過htmldocument對象才能訪問,而該對象並不是什麼時候都有效,htmldocument對象只在navigated事件觸發時纔有效,而假如用戶是按f5鍵刷新瀏覽器時呢,抱歉,navigated事件是不會觸發的。在經過了很多的嘗試後,我發現唯一可行的方法是使用並不是默認webbrowser控件一部分的downloadcomplete事件。
解決方案:
1. 實現dwebbrowserevents接口
2. 創建一個downloadcomplete事件
3. 當downloadcomplete事件觸發時,訂閱htmlwindow.error事件
4. 利用這個error事件來獲得腳本出錯的具體信息
5. 設置handled屬性爲true來阻止腳本出錯
過濾彈出窗口
彈出窗口大部分情況都是不怎麼受歡迎的或者是不適宜的,屏蔽這些彈出窗口需要一些額外的信息。當用戶使用windows xp sp2或者windows 2003 sp1 或更高版本時,newwindow3事件可以提供這些輔助信息,假如這個事件沒有觸發,那麼newwindows2事件會替代該事件。當newwindow3事件觸發時,你可以檢查以下內容:
l 是否是用戶的操作才導致了新開窗口
l 用戶是否按住了覆蓋鍵(ctrl 鍵)
l 是否因爲當一個窗口正在關閉才導致顯示彈出窗口
l 獲得將要打開窗口的url地址
l 更多...
使用newwindows3事件可以很明顯的實現這個目的,假如要使用這個事件,就必須實現dwebbrowserevents2接口。
解決方案:
1. 實現dwebbrowserevents2接口
2. 創建一個新的事件和一個新的事件參數類
3. 執行這個事件並附帶適當的信息
4. 當這個事件觸發後,檢查這次的導航是否需要取消
添加多標籤頁或多窗口瀏覽功能
多標籤頁方式瀏覽在目前似乎變得越來越流行,例如在ie7中,這就是一個新增功能。實現多標籤頁方式瀏覽的難點是,你需要在當腳本或者超鏈接創建一個新窗口的時候去創建相應的新的標籤頁或子窗口,除此之外,還需要解析出多窗口或者多標籤頁的窗口名稱。(例如:<a href=”http://somesite” target=”somewindowname”/>)要實現這一點,一些自動化對象(如:newwindowx事件中的ppdisp和iwebbrowser2接口中的application)就需要從新開窗口傳回到該事件中。而訪問application屬性需要獲得iwebbrowser2接口的引用。
解決方案:
1. 重載attachinterfaces和detachinterfaces接口
2. 保存iwebbrowser2接口對象的引用
3. 創建一個application屬性來暴露該接口中的application屬性
4. 實現dwebbrowserevent2接口
5. 監聽newwindows2和/或newwindow3事件
6. 當一個事件觸發時,創建一個新的browser控件的實例
7. 將ppdisp事件參數指派給新實例的application屬性
當一個窗口被腳本關閉時需要確認
當你在jscript中調用window.close()方法,webbrowser控件很可能出現假死。因爲某種原因,他不能用於導航頁面,也不能做其他任何事情。假如我們知道它什麼時候發生可能會好一些。當它發生時會觸發一系列的事件,但是這些事件沒有給我們需要的信息。重載wndproc方法並檢測父窗口是否通知該瀏覽器已經被銷燬是唯一可行的解決方法(假如誰知道如何得到windowsclosing事件來實現這一點是更好的方法)
解決方案:
1. 重載wndproc方法
2. 檢查wm_parentnotify消息
3. 檢查wm_destriy參數
4. 假如檢測到了上述的內容,則觸發一個新的事件(這個事件在例子中稱爲quit)