ActiveX, Second Thread, Event

问题是这样的,我要编写一个ActiveX,这个ActiveX要嵌入在网页里面并且该ActiveX要做一件耗时的计算。
 
为了避免让网页处于挂起并没有响应状态,需要使用第二个线程来进行那个耗时的计算。
 
在使用了第二个线程之后,突然发现原来可以正常Fire出来的ActiveX的Event们都不好用了。经多方考察,原来是ActiveX只能将主线程的Event发送给Container,在Second thread里面的Event尽管code都调用到了,Event是发布出来滴。
 
经友人帮助,在网上找到了这样一篇文章:
 
如果你写的是windowless的ActiveX, 请特别注意最后一段。
 

 
 
SAMPLE:   Firing   Events   From   a   Second   Thread  
   
  ---------------------------------------------------------------------  
  The   information   in   this   article   applies   to:  
   
    -   Microsoft   Visual   C++,   32-bit   Edition   versions   4.0,   4.1,   4.2  
  ---------------------------------------------------------------------  
   
  SUMMARY  
  =======  
   
  MFC   based   ActiveX   controls   typically   fire   their   events   from   the   same   thread  
  that   implements   the   sink   interface   of   the   container   that   the   events   are    
  being   fired   to.  
   
  Sometimes,   it   is   desirable   to   start   a   second   thread   in   an   ActiveX   control  
  which   will   fire   events   to   the   container.   Since   MFC   ActiveX   controls  
  use   the   Apartment   threading   model,   special   consideration   must   be   taken  
  into   account   when   firing   events   from   a   secondary   thread.  
   
  MORE   INFORMATION  
  ================  
   
  An   MFC   based   ActiveX   control   supports   events   by   implementing   the  
  IConnectionPointContainer   and   IConnectionPoint   interfaces,   as   well   as  
  supplying   information   about   it's   event   interface   in   it's   type   information.  
  When   an   MFC   based   ActiveX   control   is   embedded   in   a   container   that   supports  
  events,   that   container   will   dynamically   construct   a   sink   interface   that   has  
  all   of   the   methods   specified   in   the   control's   type   information   for   it's  
  event   interface.   Once   the   container   constructs   it's   sink   interface,   it  
  will   pass   a   pointer   to   that   interface   to   the   ActiveX   control.   The   ActiveX  
  control   will   use   it's   implementation   of   IConnectionPoint   to   communicate  
  through   the   now   hooked   up   sink   interface   that   was   constructed   by   the  
  container.   This   sample   will   demonstrate   how   to   call   methods   of   the  
  container's   sink   interface   from   a   second   thread.  
   
  The   two   most   important   things   to   consider   when   starting   a   new   thread   to  
  fire   events   from   in   an   ActiveX   control   are:  
   
  1.   MFC   based   ActiveX   controls   are   in-process   objects   (implemented   in   a    
        DLL).    
  2.   MFC   based   ActiveX   controls   use   the   Apartment   threading   model.  
   
  The   Apartment   threading   model   specifies   that   all   threads   that   want   to   use  
  OLE   services   must   initialize   OLE   in   their   thread   prior   to   using   OLE  
  services.   Also,   if   a   thread   wants   to   use   a   pointer   to   an   interface   that   is  
  either   implemented   by   a   different   thread   of   the   same   process   or   has   been  
  previously   marshaled   to   a   different   thread   of   the   same   process,   that  
  pointer   must   be   marshaled   to   the   requesting   thread.   In   the   Apartment  
  threading   model,   hidden   windows   are   created   to   synchronize   requests   from  
  other   threads   to   the   thread   being   called.   This   means   that   all  
  communication   between   threads   will   be   done   by   using   hidden   windows   and  
  Windows   messages   in   the   Apartment   model.  
   
  There   are   two   possible   ways   to   fire   events   from   a   second   thread   in   an  
  ActiveX   control   (or   any   other   in-proc   server   that   implements   connection  
  points)   under   the   Apartment   threading   model.   The   first   is   to   make   the  
  interface   call   from   the   second   thread   by   calling   the   event   sink's   method  
  from   the   second   thread.   The   second   is   to   have   the   second   thread   post   a  
  message   to   the   first   thread   when   it   is   ready   to   fire   the   event,   and   have  
  the   first   thread   fire   the   event.  
   
  The   first   method   mentioned   above   is   not   the   optimal   way   to   fire   an   event  
  from   a   second   thread.   This   is   because   for   the   second   thread   to   fire   the    
  event,   it   must   make   a   call   on   an   interface   pointer   that   is   held   by   the    
  thread   that   initialized   the   control.   This   means   that   the   interface   pointer    
  that   will   be   used   to   fire   the   event   must   be   marshaled   to   the   second   thread    
  which   will   cause   OLE   to   set   up   hidden   windows   to   communicate   between   the    
  threads.   Windows   messages   will   be   used   to   communicate   between   the   threads.    
  The   MFC   ActiveX   control   framework   is   not   set   up   to   easily   fire   events   from    
  a   second   thread.   It   is   possible   to   override   the   default   MFC   code   to   marshal    
  the   sink   interface   pointers   to   the   second   thread,   but   this   is   not    
  recommended.   The   reason   this   is   not   recommended   is   that   since   Windows   is    
  going   to   create   hidden   windows   and   use   PostMessage   to   send   messages   between    
  threads   anyway,   it   makes   more   sense   for   the   second   thread   to   post   it's   own    
  messages   to   the   first   thread   and   have   that   thread   fire   the   event.   This   code    
  can   be   easily   set   up   in   an   MFC   ActiveX   control.   Take   the   following   steps   to    
  add   a   second   thread   which   fires   events   to   the   container   in   an   MFC   ActiveX    
  control.  
   
  1.   Create   your   control   project.  
   
  2.   Using   ClassWizard,   add   a   method   that   will   start   a   second   thread   and  
        return.   The   code   for   a   method   that   starts   a   second   thread   and   returns  
        immediatly   in   an   MFC   ActiveX   control   is   shown   below.   A   global   function    
        to   serve   as   the   second   thread's   work   function   is   also   declared:  
   
        LONG   ThreadProc(LPVOID   pParam);  
   
        void   CFireeventCtrl::StartLengthyProcess()  
        {  
            DWORD   dwID;  
            HANDLE   threadHandle   =   CreateThread(NULL,NULL,  
                                                        (LPTHREAD_START_ROUTINE)ThreadProc,  
                                                        (LPVOID)this,   NULL,   &dwID);  
            TRACE("Started   the   thread   %x/n",dwID);  
        }  
   
  3.   Add   any   events   you   wish   to   fire   from   the   second   thread   using    
        ClassWizard.  
   
  4.   Define   a   custom   message   to   be   sent   from   the   second   thread.   Also,   add   a  
        message   map   entry   to   the   control's   message   map   which   will   call   the    
        message   handling   function   when   the   custom   message   is   received.   This  
        message   handler   will   fire   the   desired   event.   A   sample   of   how   to   do   this  
        in   an   MFC   ActiveX   control   is   shown   below:  
   
        //define   a   custom   message:  
        #define   WM_THREADFIREEVENT   WM_USER+101  
   
        //add   an   entry   for   the   message   to   the   message   map   of   the   control  
        BEGIN_MESSAGE_MAP(CFireeventCtrl,   COleControl)  
        //{{AFX_MSG_MAP(CFireeventCtrl)  
        //}}AFX_MSG_MAP  
        ON_OLEVERB(AFX_IDS_VERB_PROPERTIES,   OnProperties)  
        ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread)   //custom   handler    
        END_MESSAGE_MAP()  
   
        //add   a   handler   for   the   custom   message   that   will   fire   our   event  
        LRESULT   CFireeventCtrl::OnFireEventForThread(WPARAM   wParam,  
                LPARAM   lParam)  
        {  
            FireLengthyProcessDone();  
            return   TRUE;  
        }  
   
  5.   In   the   thread   procedure   for   the   second   thread,   when   it's   time   for   the  
        second   thread   to   fire   the   event,   post   the   custom   message   defined   in   step    
        3   back   to   the   main   thread.   The   event   will   be   fired.   The   following   code    
        demonstrates   this:  
   
        LONG   ThreadProc(LPVOID   pParam)  
        {  
            Sleep(2000);   //simulate   lengthy   processing  
            CFireeventCtrl   *pCtrl   =   (CFireeventCtrl*)pParam;  
            PostMessage(pCtrl->m_hWnd,  
                                    WM_THREADFIREEVENT,  
                                    (WPARAM)NULL,  
                                    (LPARAM)NULL);  
            return   TRUE;  
        }  
   
  Notice   in   the   sample   code   above   that   the   window   handle   of   the   ActiveX    
  control   is   used   as   the   target   to   which   the   message   from   the   second   thread  
  will   be   posted.   In   most   cases,   an   MFC   based   ActiveX   control   will   be   in-  
  place   active   when   it's   methods   are   called   and   will   have   a   window   handle.      
  It   is   possible,   however   for   an   ActiveX   control   to   not   have   a   window   handle,  
  such   as   in   the   case   of   a   windowless   control.   One   way   to   work   around   this  
  is   to   create   a   hidden   window   that   could   be   used   to   communicate   between  
  threads.   That   window   could   then   be   destroyed   when   the   thread   terminated.  
  The   FIREEV   sample   has   code   which   is   commented   out   in   it's  
  StartLengthyProcess   method   and   ThreadProc   thread   work   function   which  
  demonstrates   creating   a   window   which   is   wrapped   by   the   CMyWindow   class   that  
  serves   this   purpose.   Also   notice   that   PostMessage   is   used   instead   of  
  PostThreadMessage.   MFC's   message   maps   are   set   up   to   intercept   thread  
  messages   in   CWinThread   derived   classes   only.   Since   MFC   ActiveX   controls  
  are   derived   from   CWnd,   they   will   not   have   messages   sent   with  
  PostThreadMessage   routed   to   them.   Messages   sent   with   PostThreadMessage   will  
  have   a   NULL   hWnd.  
 
 
在CSDN的论坛上才找到这篇文章真不容易啊。原因是MSDN上面的这篇文章被机器翻译成了看不懂的中文。而页面上我也没有找到原文的链接。。。。
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值