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)

//參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM