僅僅用于Internet Explorer的事件
有些是僅僅可用于自動化 Internet Explorer,:
· OnQuit
- OnVisible
- OnToolBar
- OnMenuBar
- OnStatusBar
- OnFullScreen
- OnTheaterMode
大多數(shù)這些事件屬于瀏覽器用戶接口. 另外一些必須要先是或者關閉Internet Explorer才發(fā)生. 一些情形中,這些事件將在你宿主webbrowser空間的時候發(fā)生. 舉例來講,當你在你的應用程序設置MenuBar 屬性,盡管你的WebBrowser control 并沒有菜單條, OnMenuBar 事件將被激發(fā), 但是如果你顯示或者隱藏你的應用程序菜單條,OnMenuBar 事件不會激發(fā).為什么?因為你的菜單條由你控制,webbrowser對這些用戶接口項一無所知. 很長時間以來,這些相互矛盾的功能是一些混亂的根源。
其中一個事件—OnQuit—將永遠不會在你的應用程序中激發(fā).舉個例子, 察看表 Table 7-6. 注意到OnQuit 事件當用戶關閉 Internet Explorer 或者當Quit 方法被調用時激發(fā).如果你宿主改控件且用戶關閉你的應用程序, OnQuit 事件不會激發(fā).它僅僅在你自動化Internet Explorer 且用戶手動關閉瀏覽器時候發(fā)生.另外,如果你在宿主一個webbrowser控件時試圖調用Quit 方法,一個自動化錯誤將會發(fā)生.
自ActiveX控件中控制Internet Explorer 事件
通過 IWebBrowser2 接口你可以在利用vc++在ActiveX 控件中接受事件.
你可能疑惑為什么要在ActiveX控件中接受 Internet Explorer事件.之前介紹"DocumentComplete," 事件時候,我提到過你不可以在DocumentComplete event 事件被觸發(fā)前安全存取文檔.在Activex控件中獲知DocumentComplete 事件被觸發(fā)的途徑是ActiveX 控件接收 Internet Explorer并處理 DocumentComplete 事件.
除了你必須接收Internet Explorer 事件外, 你可以開發(fā)一個可導航的類瀏覽器的應用于公司intranet或者學校網(wǎng)絡.你可以在ActiveX control中自動化Internet Explorer并接受其事件。.
當你刷新一個頁面, 也許DocumentComplete 事件并不激發(fā). 當DocumentComplete 事件并未觸發(fā), ProgressChange 事件被用來控制以檢測某頁是否完成加載. 載一個簡單的web頁或者沒有嵌入幀時 ProgressChange 工作的很好.
記住 ProgressChange 右兩個參數(shù)告訴你下載操作的進度.第一個參數(shù)當下在完成時候設定為-1, 者可以幫助你檢測是否可做類打印等操作
讓我們學習一個打印控active控件,為從Internet Explorer接收事件,你必須設置事件接收,意味著你必須通過IWebBrowser2 接口以獲得實現(xiàn),如下實現(xiàn):
protected: CComPtr<IWebBrowser2> m_spWebBrowser; |
.
接下來覆蓋IOleObjectImpl 的SetClientSite方法的實現(xiàn). SetClientSite 放方法是在Internet Explorer通知氣客戶區(qū)的控件的時候被調用.你可用客戶區(qū)的site指針 (m_spClientSite) 存取容器并且得到IWebBrowser2 接口指針. 在SetClientSite 實現(xiàn)中, 你必須首先調用其基類版本,就想如下:
IOleObjectImpl<CPrintCtl>::SetClientSite(pClientSite); |
這些帶嗎看起來可能有些生疏, 但記住 IOleObjectImpl 是一個模版類. 為了調用它的方法, 你必須制定要求的模版參數(shù)以指示編譯器哪一個類實例在調用SetClientSite 方法時被使用. 現(xiàn)在講殘存的訪問容器和IWebBrowser2接口指針的代碼從Print方法遷移到SetClientSite 方法Now move the remaining code Print 方法將看起來如下:
STDMETHODIMP CPrintCtl::Print() { ATLASSERT(m_spWebBrowser); HRESULT hr = E_FAIL; if (m_spWebBrowser) { hr = m_spWebBrowser->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); } return hr; } |
而 SetClientSite 方法將接收事件,SetClientSite 講看起來如下:
注意
你不能夠再FinalConstruct m方法中接收事件因為此時客戶站點還未設定。
STDMETHODIMP CPrintCtl::SetClientSite(IOleClientSite* pClientSite) { HRESULT hr = IOleObjectImpl<CPrintCtl>::SetClientSite(pClientSite); if (!pClientSite) { return hr; } CComPtr<IOleContainer> spContainer; m_spClientSite->GetContainer(&spContainer); ATLASSERT(spContainer); if (SUCCEEDED(hr)) { // Set up the event sink. // CComQIPtr<IServiceProvider, &IID_IServiceProvider> spServiceProvider(spContainer); ATLASSERT(spServiceProvider); if (spServiceProvider) { spServiceProvider->QueryService(SID_SInternetExplorer, IID_IWebBrowser2, (void**)&m_spWebBrowser); ATLASSERT(m_spWebBrowser); if (m_spWebBrowser) { AtlAdvise(m_spWebBrowser, GetUnknown(), DIID_DWebBrowserEvents2, &m_dwCookie); } } } return hr; } |
注意到在AtlAdvise 調用時你必須建立protected 或者private DWORD的數(shù)據(jù)成員以掌握返回自AtlAdvise 方法的cookie. CprintCtl 類的構造函數(shù)初始化改成員為0. 盡管我們注意到CPrintCtl::SetClientSite 方法使用IOleObjectImpl::SetClientSite 方法的返回值. 此方法并不檢查已被調用的返回值因為CPrintCtl::SetClientSi將 反射客戶站點的設定狀態(tài).
最好, 我們檢查pClientSite 的返回值,輸入?yún)?shù)是NULL. 如果這樣,我們當Internet Explorer 卸載這些控時, 他調用SetClientSite w設置為NULL. 或者告訴你已經(jīng)從站點解除, 所以包含一個接口, IWebBrowser2 容器不需要一定執(zhí)行。.
因為當你完成任務時應當關閉任務的站點, 也包含某個控件被卸載時。檢查pClientSite 是否為NULL,以便放置AtlUnadvise 方法. 記住pClientSite在控件被卸載時為 NULL. 看起來如下:
if (!pClientSite) { ATLASSERT(m_spWebBrowser); if (m_spWebBrowser) AtlUnadvise(m_spWebBrowser, DIID_DWebBrowserEvents2, m_dwCookie); return hr; } |
現(xiàn)在你可以使用AtlAdvise接收事件,讓我們控制事件.為此你必須覆蓋重寫IDispatchImpl 的Invoke 方法. 典型的,你將為你的時間建立一個單獨的類因為 Internet Explorer 事件的DISPIDs 必須同你的控件的DISPIDs 不同.但在此你可以簡單在 CPrintCtl 類中來實現(xiàn).實現(xiàn)Invoke (入代碼所示)以控制ProgressChange 事件.在事件句柄, 如果progres的總數(shù)設定為 -1,設定一個標志變量指示已被打印.
STDMETHODIMP CPrintCtl::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { if (riid != IID_NULL) return DISP_E_UNKNOWNINTERFACE; if (!pDispParams) return DISP_E_PARAMNOTOPTIONAL; switch (dispidMember) { // // The parameters for this DISPID: // [0]: Maximum progress - VT_I4 // [1]: Amount of total progress - VT_I4 // case DISPID_PROGRESSCHANGE: if (pDispParams->cArgs != 0) { // Make sure that you access the // correct data member of the rgvarg array. // To do this, check the type of data to // make sure it is correct. // if (pDispParams->cArgs > 1 && pDispParams->rgvarg[1].vt == VT_I4 && pDispParams->rgvarg[0].vt == VT_I4) { if (-1 == pDispParams->rgvarg[1].lVal) m_fCanBePrinted = TRUE; } } break; default: // Call the base class implementation of Invoke // so that IPrintCtl methods and properties will // work correctly. // IDispatchImpl<IPrintCtl, &IID_IPrintCtl, &LIBID_ATLPRINTLib>::Invoke(dispidMember, riid, lcid, wFlags, pDispParams, pvarResult, pExcepInfo, puArgErr); break; } return S_OK; } |
在 ProgressChange 事件處理中,當Progress 參數(shù)(pDispParams->rgvarg[1].lVal) 是-1, 我們設置一個變量告訴控件問打光在完成可以打印. FCanBePrinted 就是我們要設定的變量。
現(xiàn)在當用戶試圖調用Print 方法打印文檔,你可以檢查變量以確定是否可打印. 此處為 Print 方法的代碼:
STDMETHODIMP CPrintCtl::Print() { if (!m_fCanBePrinted) { ::MessageBox(NULL, _T("The page is not ready to be printed."), _T("PrintCtl"), MB_OK); return E_FAIL; } ATLASSERT(m_spWebBrowser); HRESULT hr = E_FAIL; if (m_spWebBrowser) { hr = m_spWebBrowser->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); } return hr; } |