大家都知道通过Idispatch接口可使C++与动态语言交互, 本文分别列出各种交互方法,并着重讲解我说喜欢的一种方法,希望给网友们一些帮助,同时欢迎大家推敲和讨论
1、连接点事件,此法请参考vckbase杨老师博客
2、事件和通知,参考vckbase杨老师博客
上述两法的弊端在于:客户必须实现一个接收器,对于不同的语言实现接收器的方式各不同,如js接收器必须用特定的html标签标识出来,且只能是嵌入在html文档里面,不适和单独的js脚本,此法使用如下:
<script language= "javascript " for= "window " event= "onload ">
也可下载示例代码看看每种接收器的具体实现:atl连接点、c++接收器、js接收器
总之,使用连接点有太多不便,主要是不灵活,我不大喜欢,其实,只要想一下,既然js可以调用我的c++函数, 说明js可以认识c++函数,那么我的c++函数一定能通过相逆的方式认识JS函数, 也许直接通过回调函数即可完成, 没错, 下面我要讲的就是回调函数。
3、回调函数。此法的强大之处在于,主要你能调用我的C++函数, 我就能调用你给的回调函数, 此法的好处:简单、通用。
上代码:
新建一个ATL工程, 添加ATL简单对象CB,给CB添加接口SetCallBack、Test、Test1
// CB.cpp : CCB 的实现
#include "stdafx.h"
#include "CB.h"
#include <atlstr.h>
#include <dispex.h>
// CCB
IDispatch* s_spCallback;//手动添加, 用来保存js传过来的回调函数
STDMETHODIMP CCB::SetCallBack(VARIANT scriptcb)
{
// TODO: 在此添加实现代码
if (scriptcb.vt == VT_DISPATCH)
{
s_spCallback = scriptcb.pdispVal;
}
return S_OK;
}
STDMETHODIMP CCB::Test(LONG l) //测试回调函数
{
// TODO: 在此添加实现代码
CComVariant avarParams[1];
avarParams[0] = l; //指定回调函数的参数
DISPPARAMS params = { avarParams, NULL, 1, 0 };
if(s_spCallback)
{
HRESULT hr = s_spCallback->Invoke(0,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
¶ms, NULL, NULL, NULL);
}
return S_OK;
}
STDMETHODIMP CCB::Test1(VARIANT v)
{
// TODO: 在此添加实现代码
//CString str;
//str.Format(_T("%d"), v.vt);
//::MessageBox(NULL, str, _T(""), 0);
CComQIPtr<IDispatchEx> pParamEx = v.pdispVal;
if( !pParamEx )
return S_OK;
DISPID dispid;
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
HRESULT hr = pParamEx->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid);
while (hr == NOERROR)
{
BSTR bstrName = NULL;
VARIANT var;
hr = pParamEx->GetMemberName(dispid, &bstrName);
pParamEx->InvokeEx(dispid, LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET, &dispparamsNoArgs,
&var, NULL, NULL);
::MessageBox(NULL, var.bstrVal, _T(""), 0);
SysFreeString(bstrName);
hr = pParamEx->GetNextDispID(fdexEnumAll, dispid, &dispid);
}
return S_OK;
}
新建一个js脚本:
function callback(i)
{
WScript.echo(i);
}
var obj = new ActiveXObject("TestJsCallBack.CB");
//var obj = new ActiveXObject("TestJsCallBack.CB.1")
obj.SetCallBack(callback)
obj.Test(456)//测试回调函数
var para = {"111":"111value","222":"222value"};
obj.Test1(para)//测试C++解析json对象
在自定义类中添加头文件
#include "dispex.h"
在idl文件中 包含IDL文件
import "dispex.idl";
其实两种语言的交互无非要完成以下功能:1、能相互调用对方函数
2、能相互识别对方的自定义类型
从上述的Test1函数看出使用IdispatchEx可以解析js传给C++的自定义类型, 而js里面的这句话var obj = new ActiveXObject("TestJsCallBack.CB");告诉我们, C++将一个类暴露给了js
综上所述,IDiptch是不仅可以将C++接口暴露给脚本语言, 还可以解析脚本语言的函数或者对象, 实现二者相互调用