MFC Activex OCX Javascript 互相访问问题,线程回调javascript

//比较好的教程 
 
ocx 在 win7 系统会出现注册需要管理员权限的问题,这时候需要用管理员身份运行 cmd,然后运行 regsvr32注册。
 
很麻烦
 
尝试使用 nsis 做成安装包, 采用 regdll 注册 ocx, 成功。
 
 

ocx和外面的程序交互主要通过提供方法属性 + 事件

方法属性可以提供给js调用,

事件可以给js 通过下面的方式进行回调注入
<object id="xxx"></object>
<script language="JavaScript" for="xx" Event="eventFunction(x)"> 
alert(x);
</script> 
 
或者
document.getElementByIdx_x(xx).attachEvent("eventFunction",function(x,y){
alert(x);
});


这两种功能都可以在类视图里面选择   XXXCtrl,右键选择 add ,会出现 方法属性事件
按照wizard进行添加就好。

主要记录一下如果ocx创建了线程,想通过事件回调js的话,会出现问题。
这时候解决方法就是通过 PostMessage(WM_THREADFIREEVENT,(WPARAM)NULL,(LPARAM)NULL); 下面的看看应该懂了

//-------------------------
SAMPLE:   Firing   Events   From    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    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    secondary   thread.   
    
  MORE   INFORMATION   
  ================   
    
  An   MFC   based   ActiveX   control   supports   events   by   implementing   the   
  IConnectionPointContaine  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    container   that   supports   
  events,   that   container   will   dynamically   construct    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    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    second   thread.   
    
  The   two   most   important   things   to   consider   when   starting    new   thread   to   
  fire   events   from   in   an   ActiveX   control   are:   
    
  1.   MFC   based   ActiveX   controls   are   in-process   objects   (implemented   in      
        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    thread   wants   to   use    pointer   to   an   interface   that   is   
  either   implemented   by    different   thread   of   the   same   process   or   has   been   
  previously   marshaled   to    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    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    
  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    second   thread.   This   is   because   for   the   second   thread   to   fire   the     
  event,   it   must   make    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    
   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    second   thread   which   fires   events   to   the   container   in   an   MFC   ActiveX    
  control.   
    
  1.   Create   your   control   project.   
    
  2.   Using   ClassWizard,   add    method   that   will   start    second   thread   and   
        return.   The   code   for    method   that   starts    second   thread   and   returns   
        immediatly   in   an   MFC   ActiveX   control   is   shown   below.    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    custom   message   to   be   sent   from   the   second   thread.   Also,   add    
        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.    sample   of   how   to   do   this   
        in   an   MFC   ActiveX   control   is   shown   below:   
    
        //define    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    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     
         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    window   handle.       
  It   is   possible,   however   for   an   ActiveX   control   to   not   have    window   handle,   
  such   as   in   the   case   of    windowless   control.   One   way   to   work   around   this   
  is   to   create    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    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    NULL   hWnd.

----------------------------------//

里面提到的 hWnd,如果在IE使用空间,这个窗口句柄是空的,会导致回调照样失败,
这时候需要重载 OnSetClientSite

void CMyControl::OnSetClientSite()
{
// It doesn't matter who the parent window is or what the size of
// the window is because the control's window will be reparented
// and resized correctly later when it's in-place activated.
if (m_pClientSite)
    VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0), CRect(0,0,0,0)));
COleControl::OnSetClientSite();
}

这样,整个流程就走通了。
js调用 ocx, ocx回调js 全部走通。

在Windows   XP中,可以在任务栏上看到控件的窗口
解决的方法是尽可能用GetForegroundWindow替代GetDesktopWindow(GetForegroundWindow有时返回NULL)

//参考

你可能感兴趣的:(JavaScript)