仅仅用于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;
}
|