ActiveX控件中访问文档对象模型

知识库文章Q172763   INFO:   Accessing   the   Object   Model   from   Within   an   ActiveX   Control   描述了这个问题的解决方案。可以看到,可以同样使用IOleClientSite来和IE这个控件容器交互。可以使用IOleClientSite::GetContainer得到网页所在HTML文档对象的IOleContainer接口,然后再查询其他接口,例如IHTMLDocument2来进行对DHTML对象模型的访问。   
    
    
  问题:在IE中ActiveX控件的WM_CREATE和WM_DESTORY处理函数没有被调用   
    
  概述   
    
  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   >   }   
    
  重现问题的步骤   
    
    使用MFC   或者ATL创建一个ActiveX控件     
    添加这两个消息的处理函数     
    使用IE作为调试程序   
    
    参考   
    
  ActiveX   Control   Containers(Internet   Development   SDK)     
  KB   Q195188   PRB:   ActiveX   Control   Window   Is   Not   Created   Until   Visible   in   Internet   Explorer     
  Notes   on   Implementing   an   OLE   Control   Container(Kraig   Brockschmidt)     
  Introduction   to   ActiveX   Controls   (Internet   Development   SDK)     
  Reusing   MSHTML   (Internet   Development   SDK)     
  用ATL和MFC来创建ActiveX控件(George   Shepher   
    
  Inside   OLE,   第二版,   Kraig   Brockschmidt著   (微软出版社)     
  Understanding   ActiveX   and   OLE,   David   Chappell著   (微软出版社)     
  Inside   COM,   by   Dale   Rogerson著   (微软出版社)   d)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值