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