当前位置:编程学习 > JS >>

Com组件调用JS代码并传递多个参数个JS函数

项目中经常碰到JS与Com组件交互的问题,通过查找网络资料和项目实际需要,总结如下:
 
一、Com组件简单回调JS代码
JS中定义函数
 
[javascript]  
  function printMsg(msg1, msg2, msg3, msg4, msg5) {  
  
      alert(msg1);  
alert(msg2);  
alert(msg3);  
alert(msg4);  
alert(msg5);  
  }   
Com组件中定义函数接口,以便将JS中定义的函数作为参数传递给Com组件
 
头文件中定义IDispatch接口:
 
[cpp] 
static CComPtr<IDispatch> m_spCallback;  
[cpp]  
STDMETHODIMP CJSCallBack::SetJsCallbackFunc(VARIANT scriptCallback)  
{  
    AFX_MANAGE_STATE(AfxGetStaticModuleState());  
  
    // TODO: 在此添加实现代码  
    if (scriptCallback.vt == VT_DISPATCH)  
    {  
        m_spCallback = scriptCallback.pdispVal;  
    }  
  
  
    return S_OK;  
}  
 
 
在JS中调用SetJsCallbackFunc接口注册回调函数
 
[javascript]  
var obj = new ActiveXObject("ComForJS.JSCallBack.1");   
[javascript] view plaincopy
result = obj.SetJsCallbackFunc(printMsg);     
 
 
Com组件中调用JS函数:
 
[cpp]  
void CJSCallBack::CallJsFunction()  
{  
    CComVariant avarParams[5];  
  
    avarParams[0] = “AAA”; //指定回调函数的参数  
    avarParams[1] = "BBB";  
    avarParams[2] = "CCC";  
    avarParams[3] = "DDD";  
    avarParams[4] = "EEE";  
  
    DISPPARAMS params = { avarParams, NULL, 5, 0 };  
    if(m_spCallback)  
    {  
        HRESULT hr = m_spCallback->Invoke(0,   
            IID_NULL,   
            LOCALE_USER_DEFAULT,   
            DISPATCH_METHOD,   
            ¶ms, NULL, NULL, NULL);       
    }  
}  
几点注意的地方:
 
1,DISPPARAMS params = { avarParams, NULL, 5, 0 },中的第三个参数将决定要传递到JS函数中的参数的个数
 
2,在JS函数中参数的顺序与Com组件中赋值的顺序是反的,根据本例代码,参数数组中第一个是"AAA",最后一个是"EEE",但是实际在JS代码中,msg1的值是"EEE",msg5的值是"AAA"
 
调用过程:
 
[javascript]  
obj.Print("AAA",0);  
[cpp] view plaincopy
STDMETHODIMP CJSCallBack::Print(BSTR bstrToPrint, LONG lWait)  
{  
    AFX_MANAGE_STATE(AfxGetStaticModuleState());  
  
    CallJsFunction();         
  
    return S_OK;  
}  
可以发现,以上调用是单线程调用,那么,如果在Com组件中,需要多线程操作,并且要在别的线程完成一定任务之后才需要调用JS函数,而在子线程是没有办法直接调用在主线程中注册的JS函数的,又该如何处理呢?
 
 
 
二、Com组件中,多线程调用JS函数
针对这个问题,查阅了大量资料,基本上都是关于IDispatch接口在多线程中使用需要列集散集等概念,可能理解能力较差,最终也没能够通过这样的方式来解决实际项目中的问题,后来联想到以前项目中曾经用到过的消息窗口,于是决定尝试一番:
 
定义MsgWnd类:
 
[cpp]  
class CJSCallBack;//接口类  
class MsgWnd : public CWnd  
{  
public:  
    MsgWnd() {}  
    MsgWnd( CJSCallBack* p );  
    ~MsgWnd() {}  
protected:  
    afx_msg LRESULT OnRecvMsg(WPARAM wParam, LPARAM lParam);  
    DECLARE_MESSAGE_MAP()  
private:  
    MsgWnd(const MsgWnd&);  
    MsgWnd& operator=(const MsgWnd&);  
    CJSCallBack* m_pParent;  
  
};    
为MsgWnd类实现构造函数以及消息处理函数,并设置MessageMap
 
[cpp]  
#define WM_COMM WM_USER+200  
  
BEGIN_MESSAGE_MAP(MsgWnd, CWnd)      
    ON_MESSAGE(WM_COMM, OnRecvMsg)  
END_MESSAGE_MAP()  
  
LRESULT MsgWnd::OnRecvMsg(WPARAM wPar, LPARAM lPar)  
{  
    if ( NULL != m_pParent )  
    {  
        m_pParent->CallJsFunction();//调用Parent,也就是接口类中的函数  
    }  
    return 1;  
}  
  
MsgWnd::MsgWnd( CJSCallBack* p )  
{  
    if ( NULL != p )  
    {  
        m_pParent = p;  
    }  
}  
 
 
在接口类中声明消息窗口:
 
[cpp] 
MsgWnd* m_pMsgWnd;  
[cpp] 
声明线程函数:  
[cpp]  
<pre class="cpp" name="code">static UINT CallJspFunctionThread(LPVOID param);</pre>  
定义线程函数:
 
[cpp] 
UINT CJSCallBack::CallJspFunctionThread(LPVOID param)  
{  
    CJSCallBack* pCallBack = (CJSCallBack*)param;  
    while(m_bRunThread)  
    {  
        while(m_bPrint)  
        {                 
            MsgWnd* pMsgWnd = pCallBack->GetMsgWnd();  
            if ( NULL != pMsgWnd )  
            {  
                pMsgWnd->PostMessage( WM_COMM );  
            }                             
        }  
        sleep(20000);  
    }  
  
    return 0;  
}  
 
创建消息窗口并启动线程函数:
补充:web前端 , JavaScript ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,