僅僅用于Internet Explorer的事件
有些是僅僅可用于自動化 Internet Explorer,:
· OnQuit
- OnVisible
- OnToolBar
- OnMenuBar
- OnStatusBar
- OnFullScreen
- OnTheaterMode
大多數這些事件屬于瀏覽器用戶接口. 另外一些必須要先是或者關閉Internet Explorer才發生. 一些情形中,這些事件將在你宿主webbrowser空間的時候發生. 舉例來講,當你在你的應用程序設置MenuBar 屬性,盡管你的WebBrowser control 并沒有菜單條, OnMenuBar 事件將被激發, 但是如果你顯示或者隱藏你的應用程序菜單條,OnMenuBar 事件不會激發.為什么?因為你的菜單條由你控制,webbrowser對這些用戶接口項一無所知. 很長時間以來,這些相互矛盾的功能是一些混亂的根源。
其中一個事件—OnQuit—將永遠不會在你的應用程序中激發.舉個例子, 察看表 Table 7-6. 注意到OnQuit 事件當用戶關閉 Internet Explorer 或者當Quit 方法被調用時激發.如果你宿主改控件且用戶關閉你的應用程序, OnQuit 事件不會激發.它僅僅在你自動化Internet Explorer 且用戶手動關閉瀏覽器時候發生.另外,如果你在宿主一個webbrowser控件時試圖調用Quit 方法,一個自動化錯誤將會發生.
自ActiveX控件中控制Internet Explorer 事件
通過 IWebBrowser2 接口你可以在利用vc++在ActiveX 控件中接受事件.
你可能疑惑為什么要在ActiveX控件中接受 Internet Explorer事件.之前介紹"DocumentComplete," 事件時候,我提到過你不可以在DocumentComplete event 事件被觸發前安全存取文檔.在Activex控件中獲知DocumentComplete 事件被觸發的途徑是ActiveX 控件接收 Internet Explorer并處理 DocumentComplete 事件.
除了你必須接收Internet Explorer 事件外, 你可以開發一個可導航的類瀏覽器的應用于公司intranet或者學校網絡.你可以在ActiveX control中自動化Internet Explorer并接受其事件。.
當你刷新一個頁面, 也許DocumentComplete 事件并不激發. 當DocumentComplete 事件并未觸發, ProgressChange 事件被用來控制以檢測某頁是否完成加載. 載一個簡單的web頁或者沒有嵌入幀時 ProgressChange 工作的很好.
記住 ProgressChange 右兩個參數告訴你下載操作的進度.第一個參數當下在完成時候設定為-1, 者可以幫助你檢測是否可做類打印等操作
讓我們學習一個打印控active控件,為從Internet Explorer接收事件,你必須設置事件接收,意味著你必須通過IWebBrowser2 接口以獲得實現,如下實現:
protected: CComPtr<IWebBrowser2> m_spWebBrowser; |
.
接下來覆蓋IOleObjectImpl 的SetClientSite方法的實現. SetClientSite 放方法是在Internet Explorer通知氣客戶區的控件的時候被調用.你可用客戶區的site指針 (m_spClientSite) 存取容器并且得到IWebBrowser2 接口指針. 在SetClientSite 實現中, 你必須首先調用其基類版本,就想如下:
IOleObjectImpl<CPrintCtl>::SetClientSite(pClientSite); |
這些帶嗎看起來可能有些生疏, 但記住 IOleObjectImpl 是一個模版類. 為了調用它的方法, 你必須制定要求的模版參數以指示編譯器哪一個類實例在調用SetClientSite 方法時被使用. 現在講殘存的訪問容器和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的數據成員以掌握返回自AtlAdvise 方法的cookie. CprintCtl 類的構造函數初始化改成員為0. 盡管我們注意到CPrintCtl::SetClientSite 方法使用IOleObjectImpl::SetClientSite 方法的返回值. 此方法并不檢查已被調用的返回值因為CPrintCtl::SetClientSi將 反射客戶站點的設定狀態.
最好, 我們檢查pClientSite 的返回值,輸入參數是NULL. 如果這樣,我們當Internet Explorer 卸載這些控時, 他調用SetClientSite w設置為NULL. 或者告訴你已經從站點解除, 所以包含一個接口, IWebBrowser2 容器不需要一定執行。.
因為當你完成任務時應當關閉任務的站點, 也包含某個控件被卸載時。檢查pClientSite 是否為NULL,以便放置AtlUnadvise 方法. 記住pClientSite在控件被卸載時為 NULL. 看起來如下:
if (!pClientSite) { ATLASSERT(m_spWebBrowser); if (m_spWebBrowser) AtlUnadvise(m_spWebBrowser, DIID_DWebBrowserEvents2, m_dwCookie); return hr; } |
現在你可以使用AtlAdvise接收事件,讓我們控制事件.為此你必須覆蓋重寫IDispatchImpl 的Invoke 方法. 典型的,你將為你的時間建立一個單獨的類因為 Internet Explorer 事件的DISPIDs 必須同你的控件的DISPIDs 不同.但在此你可以簡單在 CPrintCtl 類中來實現.實現Invoke (入代碼所示)以控制ProgressChange 事件.在事件句柄, 如果progres的總數設定為 -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 參數(pDispParams->rgvarg[1].lVal) 是-1, 我們設置一個變量告訴控件問打光在完成可以打印. FCanBePrinted 就是我們要設定的變量。
現在當用戶試圖調用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; } |