分享

Activex感知网页关闭事件

 ThinkTank_引擎 2015-02-11

概述

IE直到控件第一次可见的时候才创建ActiveX控件,调用WM_CREATE的处理代码。在离开或者关闭页面的时候也没有调用WM_DESTORY的处理代码。在控件大小是0*0的时候也有同样的问题。如果你在这之前(例如window.onload事件的处理代码中)访问控件的窗口或者子窗口,那么不会成功。

原因

大多数ActiveX控件框架,例如MFC和ATL,在本地激活ActiveX控件时创建控件。基于性能上的考虑,直到控件第一次可见的时候,IE才本地激活ActiveX控件。这样包含ActiveX控件的网页载入更加迅速,占用内存更少。这也使得ActiveX控件的WM_CREATE处理代码直到控件第一次可见的时候才被调用。

如果控件支持非窗口激活,那么IE会以非窗口激活方式创建控件,这样在离开或者关闭页面的时候控件的WM_DESTORY处理代码不会被调用。

解决方案

IE在初始化或者退出页面的时候会调用页面中的ActiveX控件的IOleObject::SetClientSite的实现,无论控件是否被本地激活。在初始化页面的时候,传递的指针是宿主的IOleClientSite 接口指针,在离开或者关闭页面的时候,传递的指针是空指针。可以根据这个指针来判断控件的状态,并且执行初始化或者清除的代码。

MFC

MFC对IOleObject::SetClientSite()的实现包含对虚函数COleControl::OnSetClientSite()的调用。这时候可以根据m_pClientSite是否为空指针来判断控件是被加载还是被清除。

// CMyControl 派生于COleControl.
void CMyControl::OnSetClientSite()
{
    if (m_pClientSite)
//父窗口及其大小并不重要,因为控件在本地激活时会自动重画和重新定位。
       VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0), CRect(0,0,0,0)));
    else
        DestroyWindow();
    COleControl::OnSetClientSite();
}

ATL

ATL对IOleObject::SetClientSite()的实现有一个IOleClientSite类型的参数(MFC在对IOleObject::SetClientSite()的实现中保存这个指针到COleControl::m_pClientSite),直接拿来判断就行了。同时,ATL没有重新设置控件的父窗口,所以控件需要手动进行本地激活。

// CMyControl 派生于CComControl
STDMETHOD(SetClientSite)(IOleClientSite *pClientSite)
{
    if (pClientSite)
    {
        RECT rc = {0,0,0,0};
        // Don't have access to the container's window so just use the
        // desktop. Window will be resized correctly during in-place
        // activation.
        HWND hWnd = CreateControlWindow(::GetDesktopWindow(), rc);
        _ASSERT (hWnd);
    }
    else
        ::DestroyWindow(m_hWnd);
     return IOleObjectImpl::SetClientSite (pClientSite);
}

HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect)
{
     // Get the container's window. _ASSERT (m_spClientSite);
     LPOLEINPLACESITE pInPlaceSite = NULL;
     HRESULT hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&pInPlaceSite);
     _ASSERT (SUCCEEDED (hr) && pInPlaceSite);
     HWND hParent = NULL;
     hr = pInPlaceSite->GetWindow (&hParent);
     _ASSERT (SUCCEEDED (hr) && hParent);
     pInPlaceSite->Release ();
     // Set container window as our parent window
     SetParent (hParent);  < BR >      return CComControlBase::InPlaceActivate(iVerb, prcPosRect);  < BR >
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多