由Internet Explorer 5激發(fā)事件
如你所知, Internet Explorer像其他COM對(duì)象一樣激發(fā)事件—通過連接點(diǎn).但實(shí)際上Internet Explorer如何激發(fā)事件呢?每次 Internet Explorer需要向客戶提供關(guān)于當(dāng)前活動(dòng)狀態(tài)的信息, Internet Explorer 激發(fā)通過DWebBrowserEvents2 連接點(diǎn)激發(fā)一個(gè)事件. (之前到版本 4, Internet Explorer 通過 DWebBrowserEvents 接口激發(fā)事件.但到了版本4.x和5, Internet Explorer 通過 DWebBrowserEvents2 連接點(diǎn).)
注意
如何領(lǐng)會(huì)到Internet Explorer加法那些事件?最佳途徑是MSDN Online Web Workshop. 另外采用 OLE-COM Object Viewer
不像WebBrowser 控件 和 Internet Explorer的其他接口,是劍接口沒有繼承體系.DWebBrowserEvents 接口嚴(yán)格應(yīng)用于Internet Explorer 3. 如果你正宿主WebBrowser 控件或者自動(dòng)化Internet Explorer 5, 你可以通過此接口接收事件—但是不可掛接. DWebBrowserEvents2 接口包含的方法是為Internet Explorer 5定制的.用 DWebBrowserEvents2 替代DWebBrowserEvents,你將有更多的控制能力. 所以不要忘記接口的最后面的2.
盡管DWebBrowserEvents2 是一個(gè)事件接口, 它其實(shí)就是像IWebBrowser2 一樣的另外 COM 接口,所以它可以包含方法. (D 開頭的命名是表示這是派遣接口.一個(gè)派遣接口是一個(gè)IDispatch 接口.但不同于普通接口, 派遣接口沒有vtable.) 就像一個(gè)接口一樣,派遣接口只不過提供一些函數(shù)的定義—他們并不真實(shí)實(shí)現(xiàn).事件的實(shí)現(xiàn)由客戶提供.舉例來說,為了讓W(xué)ebBrowser 激發(fā)一個(gè)事件, 在DWebBrowserEvents2 接口中適當(dāng)定義一些方法.這些方法由客戶實(shí)現(xiàn).但WebBrowser不直接調(diào)用這些方法.換句話講, WebBrowser 并不調(diào)用DocumentComplete 方法.因?yàn)?nbsp;DWebBrowserEvents2 是派遣接口, WebBrowser 通過IDispatch::Invoke調(diào)用客戶的實(shí)現(xiàn). 早期, 當(dāng)WebBrowser 調(diào)用客戶的Invoke 實(shí)現(xiàn), WebBrowser 傳遞事件被激發(fā)的DISPID.
注意
某些工具如Visual Basic, MFC, 和 ATL 提供Invoke實(shí)現(xiàn)
表7-6 列出 WebBrowser 事件. (這些是WebBrowser 控件和Internet Explorer供有的事件,盡管有些事件僅僅用于自動(dòng)化Internet Explorer).
注意
盡管有些方法為不包含2.盡管DWebBrowserEvents2 并非繼承自WebBrowserEvents,DWebBrowserEvents2 還是匹配 DWebBrowserEvents 中被更改的,以免混淆。
注意表 7-6 重的參數(shù)有些值同樣有 VARIANT_ TRUE 或 VARIANT_FALSE. 如果你使用Visual C++,確信分派使用這些值不要使用 TRUE 或 FALSE. 如果你使用Visual Basic, 它會(huì)自動(dòng)幫助你轉(zhuǎn)換,你可以比較True和False.
現(xiàn)在來仔細(xì)看看這些事件
Table 7-6 WebBrowser 事件
私有事件 | 描述 |
BeforeNavigate2 | 在導(dǎo)航之前發(fā)生. (該事件并不在不刷新頁面的時(shí)候發(fā)生) |
CommandStateChange | 當(dāng)命令狀態(tài)改變時(shí)發(fā)生.該事件告訴你何時(shí)使能或者禁止 Back 以及Forward 菜單像或者按鈕. |
DocumentComplete | 當(dāng)整個(gè)文檔完全完成裝載時(shí)發(fā)生.如果你刷新頁面, 此事件并不激發(fā). |
DownloadBegin | 當(dāng)一個(gè)下載項(xiàng)目開始時(shí)候發(fā)生 ,此事件也在你刷新(IWebBrowser2::Refresh.)時(shí)發(fā)生 |
DownloadComplete | 黨整個(gè)下載項(xiàng)目完成是發(fā)生該事件也發(fā)生在完成刷新頁面. |
NavigateComplete2 | 當(dāng)整個(gè)導(dǎo)航完成. 該事件對(duì)應(yīng)于 BeforeNavigate2. |
NewWindow2 | 在一個(gè)新的窗口被創(chuàng)建以顯示Web頁或者其他資源的時(shí)候發(fā)生。譬如你在頁面中以新建窗口的方式打開一個(gè)連接 |
OnFullScreen | 當(dāng)FullScreen 屬性被改變時(shí)候發(fā)生.此事件攜帶一個(gè)VARIANT_ BOOL類型的輸入?yún)?shù)指示Internet Explorer 是否處于全屏(full-screen) 模式(VARIANT_TRUE) 或者處于普通模式(VARIANT_FALSE). |
OnMenuBar | 菜單條MenuBar 屬性被改變的時(shí)候發(fā)生. 一個(gè)VARIANT_ BOOL類型的輸入?yún)?shù)指 Internet Explorer的菜單條屬性是可見(VARIANT_TRUE) 或者隱藏 (VARIANT_ FALSE). |
OnQuit | 當(dāng)Internet Explorer正在退出時(shí)發(fā)生. 該事件當(dāng)用戶關(guān)閉瀏覽器或者調(diào)用Quit 方法. |
OnStatusBar | 當(dāng)StatusBar 屬性被改變的時(shí)候發(fā)生。事件攜帶VARIANT_ BOOL類型的輸入?yún)?shù) 指示Internet Explorer的狀態(tài)條是否可見 (VARIANT_TRUE)或者隱藏 (VARIANT_FALSE). |
OnTheaterMode | 當(dāng)TheaterMode 屬性被改變時(shí)發(fā)生. 事件攜帶VARIANT_ BOOL類型的輸入?yún)?shù) 指示Internet Explorer的狀態(tài)條是否可見 (VARIANT_TRUE) 或者隱藏 (VARIANT_FALSE). |
OnToolBar | 當(dāng)ToolBar屬性被改變時(shí)發(fā)生. 事件攜帶VARIANT_ BOOL類型的輸入?yún)?shù) 指示Internet Explorer的狀態(tài)條是否可見 (VARIANT_TRUE) 或者隱藏(VARIANT_FALSE). |
OnVisible | 當(dāng)WebBrowser將被顯示或者隱藏時(shí)發(fā)生。. 事件攜帶VARIANT_ BOOL類型的輸入?yún)?shù) 指示Internet Explorer的狀態(tài)條是否可見(VARIANT_TRUE) 或者隱藏 (VARIANT_FALSE). |
ProgressChange | 當(dāng)下載進(jìn)度被更新時(shí)候發(fā)生 |
PropertyChange | 當(dāng)屬性改變時(shí)候發(fā)生。典型的, 當(dāng)PutProperty 方法被調(diào)用時(shí) |
StatusTextChange | Internet Explorer 和 WebBrowser 控件改變狀態(tài)條時(shí)候發(fā)生。即使webbrowser控件沒有狀態(tài)條。 StatusTextChange 給客戶一個(gè)改變狀態(tài)條的機(jī)會(huì) |
TitleChange | .當(dāng)文檔對(duì)象的title可用或者改變的時(shí)候發(fā)生 |
BeforeNavigate2
BeforeNavigate2 就像字面上所說. 當(dāng)Internet Explorer 導(dǎo)航到一個(gè)WEB頁是激發(fā); 因此, 當(dāng)用戶輸入一個(gè) URL, 點(diǎn)擊 Back 或者 Forward 按鈕, 或者處理一個(gè)導(dǎo)航時(shí)都會(huì)發(fā)生.BeforeNavigate2 也在WebBrowser 控件導(dǎo)航類方法調(diào)用時(shí)發(fā)生, 例如 Navigate, Navigate2,GoHome, 或者 GoSearch. 也許, 該事件不會(huì)在你刷新頁面時(shí)發(fā)生. 如果頁面上有幀,BeforeNavigate2 將像頂級(jí)窗口一樣被激發(fā). BeforeNavigate2 由7個(gè)輸入?yún)?shù), 見7-7.
Table 7-7 Input Parameters of the BeforeNavigate2 Event
Parameter | Description |
pDisp | 將發(fā)生導(dǎo)航的頂級(jí)窗口或者幀的Idispatch 接口的地址 |
URL | 將導(dǎo)航至的URL |
Flags | 保留 |
TargetFrameName | 顯示資源的窗口或者幀的名字字符串,或者為NULL(如果沒有命名) |
PostData | HTTP POST 傳輸?shù)臄?shù)據(jù)地址 |
Headers | 增加的將要發(fā)給服務(wù)器的 HTTP 頭. 一般HTTP頭指定其它的服務(wù)器要求。傳送給服務(wù)器的數(shù)據(jù)類型、狀態(tài)馬等 |
Cancel | cancel 標(biāo)志的地址. 設(shè)置為TRUE可取消導(dǎo)航 |
注意打所屬參數(shù)匹配于Navigate 或者 Navigate2的調(diào)用參數(shù).如果 BeforeNavigate2 由一個(gè)或者多個(gè)導(dǎo)航類調(diào)用激發(fā),這些導(dǎo)航類的方法參數(shù) 傳遞到BeforeNavigate2 方法.
在事件的句柄函數(shù)中, 你可以使用Cancel 參數(shù)取消導(dǎo)航, 或者你可以是用pDisp 參數(shù)修改導(dǎo)航目的.設(shè)置Cancel 參數(shù)為 VARIANT_TRUE 可以取消導(dǎo)航,如果你想,你可以通過pDisp修改參數(shù)導(dǎo)航信息且導(dǎo)航到另外的位置.舉例來說,如果我們向停止當(dāng)前導(dǎo)航, 增加一些頭信息,且導(dǎo)航到原先的URL.在Visual Basic, 我們可以如下代碼實(shí)現(xiàn):
Private Sub WebBrowser1_BeforeNavigate2(ByVal pDisp As Object, _ URL As Variant, _ Flags As Variant, _ TargetFrameName As Variant, _ PostData As Variant, _ Headers As Variant, _ Cancel As Boolean) If TypeName(pDisp) = "WebBrowser" And Headers = "" Then pDisp.Stop pDisp.Navigate URL, Flags, TargetFrameName, PostData, _ Headers + "MyHeaders" Cancel = True End If End Sub |
我們需要注意以上代碼的幾個(gè)重點(diǎn).
首先你必須檢查pDisp 的類型使之確定為WebBrowser. 當(dāng)頁面包含幀, pDisp 可能不是 WebBrowser 對(duì)象由此一些導(dǎo)航會(huì)導(dǎo)致錯(cuò)誤.
其次你必須檢查確信Headers 參數(shù)是空字符串以避免無限循環(huán).記住BeforeNavigate2 每一次導(dǎo)航都會(huì)發(fā)生.因此如果你在BeforeNavigate2事件處理中調(diào)用Navigate, 另外一次 BeforeNavigate2將被激活. 在前面的代碼中, 僅僅在Headers 參數(shù)為空才調(diào)用Navigate 避免了無限循環(huán). 如果Headers 參數(shù)是空, Navigate 將攜帶非空的 Headers 參數(shù). 下一次BeforeNavigate2 北激活,Headers 將不為空; 此時(shí),我們千萬不可再次Navigate a,從而導(dǎo)致一個(gè)無限循環(huán).
第三點(diǎn)你必須調(diào)用pDisp 的Stop 方法.如果你沒做到這點(diǎn),"about:NavigationCanceled" Web 頁將會(huì)載你首次取消掉導(dǎo)航時(shí)被顯示.
CommandStateChange
CommandStateChange 是當(dāng)Internet Explorer 想通知一個(gè)應(yīng)用程序WebBrowser 命令狀態(tài)已經(jīng)改變時(shí)激發(fā).當(dāng)檢測(cè)到Forward和Back 菜單項(xiàng)和按鈕禁止或者使能時(shí)激發(fā)此事件.
CommandStateChange 事件有2個(gè)參數(shù), Command 和 Enable。 Command 輸入?yún)?shù)將要改變狀態(tài)的按鈕的表示符,可以取值—CSC_NAVIGATEFORWARD 和 CSC_NAVIGATEBACK分別表示是Forward按鈕項(xiàng)和Back項(xiàng),每次導(dǎo)航發(fā)生, CommandStateChange 事件發(fā)生并告訴你Forward 或者 Back 菜單項(xiàng)以及按鈕將使能或禁止. 舉例來說, 如果沒有Web頁在當(dāng)前導(dǎo)航后發(fā)生, Command 的值應(yīng)該為CSC_NAVIGATEFORWARD, 并且Enable 參數(shù)將等于VARIANT_FALSE.
第二個(gè)參數(shù), Enable,如果命令可用(使能) 則為VARIANT_TRUE,如果禁止則值為VARIANT_FALSE.
為說明問題,我們看看代碼。一下代碼為定義事件接收的宏聲明:
// Event sink map declaration for WebBrowser // control events. This declaration goes in the // header file for CMfcWebHostView _ MfcWebHostView.h. // DECLARE_EVENTSINK_MAP() // Initialize the event sink map and handle the // CommandStateChange event. BEGIN_EVENTSINK_MAP(CMfcWebHostView, CView) ON_EVENT(CMFCIEEvtSpyDlg, IDC_WEBBROWSER, DISPID_COMMANDSTATECHANGE, OnCommandStateChange, VTS_I4 VTS_BOOL) END_EVENTSINK_MAP() |
重要的一點(diǎn)是要通過WebBrowser控件的Create 方法來創(chuàng)建. ON_EVENT的第二個(gè)參數(shù)為你宿主的WebBrowser控件的IID.之前的例子中是NULL. 你必須為webbrowser控件聲明一個(gè)ID 且用此 ID 創(chuàng)建實(shí)例.如果不這么做,事件將不會(huì)正確工作.
你可以在工程的任何文件定義此ID. (推薦在資源頭文件resource.h.) 因?yàn)?最大的資源Id是32,779, 所以你可以如下定義WebBrowser 控件的ID:
#define IDC_WEBBROWSER 35000 |
此數(shù)高于resource.h中的任何資源ID, 因此可以確信ID 數(shù)字不會(huì)同采用ClassWizard添加的ID沖突.現(xiàn)在可以采用使用ID的 Create 方法來創(chuàng)建WebBrowser控件:
if (!m_webBrowser.Create(NULL, WS_CHILD|WS_VISIBLE, CRect(), this, IDC_WEBBROWSER)) { return -1; } |
下一步聲明OnCommandStateChange 方法,該方法將在WebBrowser控件激發(fā)CommandStateChange 事件時(shí)被調(diào)用.可聲明 如下:
void OnCommandStateChange(long lCommand, BOOL bEnable); |
在 OnCommandStateChange 方法的是現(xiàn)代碼中, 設(shè)定表示Go Forward 或者 Go Back 想得導(dǎo)航菜單項(xiàng)的數(shù)據(jù)成員為使能或者禁止. 該書據(jù)成員將被UPDATE_COMMAND_UI 句柄使用。以下為OnCommandStateChange 方法實(shí)現(xiàn):
void CMfcWebHostView::OnCommandStateChange(long lCommand, BOOL bEnable) { switch(lCommand) { // Forward command // case CSC_NAVIGATEFORWARD: m_fForwardEnabled = bEnable; break; // Back command // case CSC_NAVIGATEBACK: m_fBackEnabled = bEnable; break; default: break; } } |
聲明m_fForwardEnabled 和 m_fBackEnabled 數(shù)據(jù)變量為保護(hù)成員,類型為BOOL.同樣在構(gòu)造函數(shù)中誰的些數(shù)據(jù)成員為TRUE。.
現(xiàn)在當(dāng)Go Forward和Go Back的菜單 UPDATE_COMMAND_UI被處理, 你可以直接進(jìn)行設(shè)置. 下為示例代碼:
void CMfcWebHostView::OnUpdateNavigateGoForward(CCmdUI* pCmdUI) { pCmdUI->Enable(m_fForwardEnabled); } void CMfcWebHostView::OnUpdateNavigateGoBack(CCmdUI* pCmdUI) { pCmdUI->Enable(m_fBackEnabled); } |
DocumentComplete
當(dāng)一個(gè)文檔完整的完成下載Internet Explorer 激發(fā)DocumentComplete 事件. 僅僅當(dāng)此事件激發(fā)后 文檔對(duì)象才可安全使用.在一個(gè)無幀的Web頁情形中文檔對(duì)象是IHTMLDocument2 對(duì)象, 我們以后會(huì)討論. 當(dāng)文檔對(duì)象準(zhǔn)備好可用,他的狀態(tài)為READYSTATE_COMPLETE.
關(guān)于 DocumentComplete 事件以西擊點(diǎn)需要注意:
· 在沒有幀的web頁, DocumentComplete 事件在下載完成后激發(fā)一次.
- 在多幀的web頁,此事件激發(fā)多次.并非每一個(gè)幀激發(fā)一個(gè)事件, 但每一個(gè)幀激發(fā)DownloadBegin事件將會(huì)相應(yīng)激發(fā)DocumentComplete 事件.
- DocumentComplete又一個(gè)指向 IDispatch 的指針參數(shù), 該參數(shù)指向激發(fā)此事件的窗口. 此窗口可以是幀中的窗口
- 頂級(jí)幀在所有子幀激發(fā)了各自的DocumentComplete事件后激發(fā)自己的 DocumentComplete事件。 因此,,要看一個(gè)web頁是否完整下載完成, 你需要從該事件的處理句柄中獲取由事件產(chǎn)地過來的IDispatch 參數(shù)的IUnknown 接口。下一步,比較IUnknown 接口是否指向你正宿主的WebBrowser控件或者自動(dòng)化的IE的實(shí)例的IUnknown 接口.如果這兩個(gè)指針相同,這意味著全部HTML, 圖片images, 控件,以及諸如此類在頂級(jí)幀或者子幀的全部對(duì)象元素都被下載了.
VB中實(shí)現(xiàn)以上四點(diǎn)及其容易.僅需要檢查發(fā)送給事件的pDisp 參數(shù)事一個(gè)WebBrowser 對(duì)象. Visual Basic小心檢查這些對(duì)象的 Iunknown否為同一個(gè)對(duì)象.此處為VB代碼::
Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant) If (pDisp Is WebBrowser1.Object) Then MsgBox "The document is finished loading." End If End Sub |
實(shí)現(xiàn)以上四點(diǎn)在Visual C++ 應(yīng)用程序里較困難一點(diǎn),但你可以做到! 首先在DocumentComplete 事件的宏中如下聲明:
ON_EVENT(CMfcWebHostView, IDC_WEBBROWSER, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT) |
接下來聲明OnDocumentComplete 方法作為事件處理句柄
void OnDocumentComplete(LPDISPATCH lpDispatch, VARIANT FAR* URL); |
最后,實(shí)現(xiàn)該方法以檢測(cè) 是否頁面已經(jīng)下載,我們得到我們宿主控制bBrowser 控件的IUnknown. (注意我們不是簡(jiǎn)單獲取指向 IUnknown ,而是要調(diào)用GetControlUnknown 方法. GetControlUnknown方法返回的IUnknown 指針 實(shí)際上并不等于被宿主話的 WebBrowser控件的IUnknown. 那將返回IOleObject 接口指針.) 下一步, 獲取IUnknown 指針,如果QueryInterface 查詢得到的Dispatch 參數(shù)同Iunknown接口是同一對(duì)象,則頁面完成整個(gè)下載。.
void CMfcWebHostView::OnDocumentComplete(LPDISPATCH lpDispatch, VARIANT FAR* URL) { HRESULT hr; LPUNKNOWN lpUnknown; LPUNKNOWN lpUnknownWB = NULL; LPUNKNOWN lpUnknownDC = NULL; lpUnknown = m_webBrowser.GetControlUnknown(); ASSERT(lpUnknown); if (lpUnknown) { // Get the pointer to the IUnknown interface of the WebBrowser // control being hosted. The pointer to the IUnknown returned from // GetControlUnknown is not the pointer to the IUnknown of the // WebBrowser control. It's actually a pointer to the IOleObject. // hr = lpUnknown->QueryInterface(IID_IUnknown, (LPVOID*)&lpUnknownWB); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return; // Get the pointer to the IUnknown of the object that fired this // event. // hr = lpDispatch->QueryInterface(IID_IUnknown, (LPVOID*)&lpUnknownDC); ASSERT(SUCCEEDED(hr)); if (SUCCEEDED(hr) && lpUnknownWB == lpUnknownDC) { // The document has finished loading. // MessageBox("The document has finished loading."); } if (lpUnknownWB) lpUnknownWB->Release(); if (lpUnknownDC) lpUnknownDC->Release(); } } |
有一點(diǎn)需要注意上面的代碼我們?cè)?em>GetControlUnknown 返回的IUnknown 接口指針使用時(shí)并沒有進(jìn)行Release ,因?yàn)閎 IUnknown 指針并沒有在GetControlUnknown方法中 AddRef'.GetControlUnknown 方法僅僅返回一個(gè)IOleObject 數(shù)據(jù)成員的指針,該指針由控件站點(diǎn)類—CcontrolSite 操縱處理. 如果你釋放了IUnknown 接口指針, 載你關(guān)閉應(yīng)用程序時(shí),一個(gè)訪問違例將會(huì)發(fā)生,因?yàn)镸FC 將試圖在對(duì)象被刪除時(shí)候多釋放一次.
DownloadBegin
DownloadBegin 事件通知應(yīng)用程序一個(gè)導(dǎo)航操作開始. 一般情況下該事件在BeforeNavigate2 事件之后激發(fā), 除非導(dǎo)航操作在BeforeNavigate2 事件處理過程中被取消.容器應(yīng)當(dāng)顯示動(dòng)畫或者忙指示當(dāng)前正處于連接的DownloadBegin事件. 每一個(gè) DownloadBegin 事件有一個(gè)相應(yīng)的DownloadComplete 事件. 在刷新頁面的情形中, DownloadBegin 和 DownloadComplete 使唯一的被激發(fā)的導(dǎo)航事件.
DownloadComplete
DownloadComplete在一個(gè)導(dǎo)航操作完成時(shí)候發(fā)生, 停止, 或者失敗. 不像 NavigateComplete2僅僅當(dāng)成功導(dǎo)航才發(fā)生, DownloadComplete總是在道涵開始后激發(fā).任何在DownloadBegin 中顯示的動(dòng)畫或者忙指示將會(huì)在DownloadComplete 中停止.
NavigateComplete2
NavigateComplete2 事件在導(dǎo)航到一個(gè)超連接整個(gè)窗口或者幀集合的元素全部完成時(shí)候發(fā)生. 第一此事件發(fā)生表示文檔document已經(jīng)準(zhǔn)備好.在此事件發(fā)生后, 你可以通過Document 屬性存取文檔(document)而不接收到錯(cuò)誤.但是能夠訪問一個(gè)文檔不意味著你訪問文檔使安全的.你可以在DocumentComplete 事件激發(fā)后安全訪問文檔.
檔你需要訪問document對(duì)象但是不需要訪問文檔內(nèi)的元素,你可以在NavigateComplete2 事件中盡可能快的處理,例如當(dāng)你在文打工通過高級(jí)宿主接口. NavigateComplete2 事件有2個(gè)參數(shù)—IDispatch of 代表激發(fā)事件的對(duì)象URL 為你需要導(dǎo)航到的URL.
NewWindow2
NewWindow2 檔用戶顯示一個(gè)新窗口以進(jìn)行新導(dǎo)航顯示web頁或者其他資源時(shí)發(fā)生.在WebBrowser控件響應(yīng)柄進(jìn)行預(yù)處理 (舉例來說, 在響應(yīng)window.open 方法).
NewWindow2 也在Navigate 或者 Navigate2 方法被調(diào)用且navOpenInNewWindow 標(biāo)志被設(shè)定時(shí)發(fā)生. 檔采用文件菜單中的New Window按鈕時(shí)并不發(fā)生(Internet Explorer幀不是一個(gè) HTML 幀; 它是幀窗口.) 因此, WebBrowser 對(duì)象不知道什么時(shí)候新窗口將被打開. 因?yàn)?nbsp;NewWindow2 有時(shí)候很難使用, 所以我們來檢查它的兩個(gè)參數(shù): ppDisp and Cancel.
ppDisp 參數(shù)是接口指針, 一般是接收新WebBrowser 或者 InternetExplorer 對(duì)象的IDispatch 接口指針, 是你能夠創(chuàng)建一個(gè)Internet Explorer新實(shí)例以便能夠控制來自你的應(yīng)用程序?qū)Ш疆a(chǎn)生的新窗口. 該實(shí)例開始為新建的, 隱藏的, (暫時(shí))不可導(dǎo)航WebBrowser 或者 InternetExplorer對(duì)象. 在NewWindow2事件句柄函數(shù)返回之前, InternetExplorer 對(duì)象激發(fā)NewWindow2 事件將配置新WebBrowser對(duì)象的導(dǎo)航目標(biāo)位置.
另外參數(shù), Cancel, 時(shí)取消(Cancel)標(biāo)志的地址. 應(yīng)用程序能夠設(shè)定此參數(shù)為TRUE 以取消導(dǎo)航操作或者設(shè)定為FALSE 以允許新建窗口操作. 設(shè)定Cancel 為 TRUE 完全取消新建窗口操作和導(dǎo)航.
如果你不在NewWindow2 事件處理過程中作任何事, 新的 InternetExplorer 對(duì)象將自動(dòng)建立. 一些原因你想控制NewWindow2 事件以便控制新建InternetExplorer 對(duì)象. 為什么? 因?yàn)槟阆胂拗艻nternet Explorer的實(shí)例數(shù)量,或者你想控制創(chuàng)建的實(shí)例的事件.
以下 NewWindow2 事件控制函數(shù)中; 建立了一個(gè)新的, 隱藏的, 不可導(dǎo)航的Internet Explorer實(shí)例; 并且設(shè)定ppDisp 參數(shù)指向新實(shí)例.如果你想,你可以加入任何接收新實(shí)例事件的代碼.
void CMyEvtSink::NewWindow2(LPDISPATCH* ppDisp, BOOL* Cancel) { // Note that m_pIE is a class member of type IWebBrowser2*. HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_pIE); if (hr == S_OK) *ppDisp = (IDispatch*)pIE; // Do not set Cancel to TRUE. If you do, // the navigation will be completely canceled. } |
另外的原因控制NewWindow2 事件是由于你想你應(yīng)用程序在用戶選擇在新窗口打開一個(gè)url時(shí)進(jìn)行控制. 如果你不進(jìn)行控制NewWindow2 事件, Internet Explorer 新實(shí)例將被創(chuàng)建.
以下為控制新建窗口的vb代碼:
Private Sub WebBrowser1_NewWindow2(ppDisp As Object, Cancel As Boolean) Dim frmWB As Form1 Set frmWB = New Form1 Set ppDisp = frmWB.WebBrowser1.Object frmWB.Visible = True Set frmWB = Nothing End Sub |
在此NewWindow2事件代碼中,檔一個(gè)新常口需要被創(chuàng)建, 我們建立一個(gè)新的當(dāng)前窗體Form1的拷貝. 在此表單窗體, 相當(dāng)于Internet Explorer的新實(shí)例,將處理導(dǎo)航.
在mfc中我們需要首先加入NewWindow2 事件的映射條目到視圖類的事件映射宏. (不要忘記包含 ExDispID.h in, 那里有DISPID_NEWWINDOW2 定義.)
ON_EVENT(CMfcWebHostView, IDC_WEBBROWSER, DISPID_NEWWINDOW2, OnNewWindow2, VTS_PDISPATCH VTS_PBOOL) |
下一步聲明OnNewWindow2 方法:
void OnNewWindow2(LPDISPATCH* ppDisp, BOOL* Cancel); |
最后實(shí)現(xiàn)OnNewWindow2 方法以創(chuàng)建一個(gè)新的MfcWebHost窗口實(shí)例:
void CMfcWebHostView::OnNewWindow2(LPDISPATCH FAR* ppDisp, BOOL FAR* Cancel) { // Ensure that ppDisp is not NULL. // If it is NULL, you probably specified // VT_DISPATCH for the first parameter in // the ON_EVENT macro for NewWindow2 in // the event sink map. The correct parameter // type is VT_PDISPATCH. // ASSERT(ppDisp); if (!ppDisp) return; // Get a pointer to the application object // for this application. // CWinApp* pApp = AfxGetApp(); // Get the correct document template. // CDocTemplate* pDocTemplate; POSITION pos = pApp->GetFirstDocTemplatePosition(); pDocTemplate = pApp->GetNextDocTemplate(pos); ASSERT(pDocTemplate); // Create the new frame. CFrameWnd* pNewFrame = pDocTemplate->CreateNewFrame(GetDocument(), (CFrameWnd*)AfxGetMainWnd()); ASSERT(pNewFrame); // Activate the frame, and set its active view. // pDocTemplate->InitialUpdateFrame(pNewFrame, NULL); CMfcWebHostView* pWbView = (CMfcWebHostView*)pNewFrame->GetActiveView(); ASSERT(pWbView); *ppDisp = pWbView->m_webBrowser.GetApplication(); } |
如果你在sid或者mdi應(yīng)用程序中控制一個(gè)WebBrowser控件,實(shí)現(xiàn)OnNewWindow2 方法是復(fù)雜的且需要知道如何解決同文檔模版如何工作. 或許, 如果你在一個(gè)給予對(duì)話框的應(yīng)用程序控制一個(gè)WebBrowser控件是較為容易的.此處為示例:
void CMyDlg::OnNewWindow2(LPDISPATCH FAR* ppDisp, BOOL FAR* Cancel) { m_dlgNewWB = new CMyDlg; m_dlgNewWB->Create(IDD_MYDLG_DIALOG); *ppDisp = m_dlgNewWB->m_webBrowser.GetApplication(); } |
記住當(dāng)你完成打開的新對(duì)話框后刪除(delete) m_dlgNewWB. 且不要在CMyDlg::OnInitDialog方法中導(dǎo)航, 因?yàn)檫@樣代碼將不會(huì)工作.
ProgressChange
ProgressChange 事件通告你的應(yīng)用程序下在操作狀態(tài)已經(jīng)更新. ProgressChange 有兩個(gè)參數(shù):
· Progress. 總計(jì)有多少進(jìn)度將被展示, 如果為-1 表示整個(gè)進(jìn)度已經(jīng)完成
容器可通過此事件顯示下載進(jìn)度。
事件發(fā)生序列
下圖展示了IE的事件發(fā)生序列.但這僅僅為不包含幀的普通網(wǎng)頁瀏覽. (沒有包含諸如ProgressChange, CommandStateChange, OnToolBar, 等等事件.)不是所有事件都會(huì)被激發(fā). 但是BeforeNavigate2 和DocumentComplete 每次瀏覽都會(huì)被激發(fā).
Figure 7-5. The sequence of events fired by the WebBrowser control during a typical navigation.