JavaScript与ActiveX之间传递数据---连载三
本文研究如何在JS等脚本语言与ActiveX控件之间通信,如何传递各种类型的参数,以及COM的IDispatch接口。使用类似的方法,可以推广到其他所有脚本型语言,如LUA,AutoCad等。
本文将研究以下几个方面:
1.?????????整形数组传参
2.?????????字符串参数,字符串返回值
3.?????????修改传入字符串内容
4.?????????数组参数
5.?????????IDispatch接口介绍
6.?????????修改输入数组内容
7.?????????增加数组内容
8.?????????以数组传参方式,JS调用S4Execute( )
?
由于本文篇幅较长,所以将以连载方式进行发表,连载一主要讨论1-3点,连载二主要讨论4-6点,连载三主要讨论7-8点.
(七)增加数组内容
1.??????在COM中无法向JS中一样,直接增加数组元素。只能使用属性、方法的方式访问数组对象,并以此产生增加数组元素的效果。
2.???????JS的Array中包含push( )、?pop( )两个方法,用于在数组尾部增减元素。在COM中需要增减元素时,可通过IDispatch:: Invoke( )接口调用?"push"、"pop"方法来实现。
3.???????COM中C++定义
STDMETHODIMP CJsAtl::AddNewElement(VARIANT vArray)
{
?????????AddArrayElement(vArray.pdispVal, 123);???//?增加元素,值为?123
?????????return?S_OK;
}
?
// ****************************************************
//?向js数组中增加元素
// ****************************************************
HRESULT AddArrayElement(IDispatch* pDisp,?int?value)
{
?????????HRESULT hr = 0;
?????????DISPID??????dispid[2] = {0};
?????????CComBSTR funcName(L"push");
????????
?????????hr = pDisp->GetIDsOfNames(IID_NULL, &funcName, 1, LOCALE_USER_DEFAULT, dispid);
?????????if?(FAILED(hr))
???????????????????return?hr;
?
?????????DISPID dispidNamed = DISPID_UNKNOWN;
?????????DISPPARAMS params;
?????????params.rgdispidNamedArgs = NULL;
?????????params.cArgs = 1;
?????????params.cNamedArgs = 0;
?????????params.rgvarg =?new?VARIANTARG[1];
?????????params.rgvarg[0].vt = VT_I4;
?????????params.rgvarg[0].intVal = value;
?
????????hr = pDisp->Invoke(dispid[0], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);????????
?
?????????return?hr;
}
4.?????????JS调用
function test_add_element()
{
???????var array = new Array(0, 1, 2, 3);
???????try {
??????????????var obj = document.getElementByIdx_x("obj");
??????????????obj.AddNewElement(array);
??????????????alert("length: [" + array.length + "] " + array[array.length - 1]);
???????} catch (e) {
??????????????alert("JS ERROR: " + e.message);
???????}
}
5.?????????测试执行
原数组:{0,1,2,3}
增加后:{0,1,2,3,123}
?
(八)以数组传参方式,JS调用S4Execute( )
1.?????????本例展示如何在JS中执行精锐4锁内程序,且以数组方式处理参数。
2.?????????本例在Execute传参时,直接以整形数组表示字节数组,而不再需要Hex字符串形式,使得JS端接口更加直观。
3.?????????JS代码
???????var obj = document.getElementByIdx_x("obj");
???????var deviceID = "123";
???????var userPin = "12345678";
???????var fileID??= "0001";
???????var inBuff??????= new Array(1, 2, 3, 4);
???????var outBuff = new Array(0, 0, 0, 0);
???????var ret = 0;
???????try {
??????????????ret = obj.OpenLock(deviceID);
??????????????ret = obj.ChangeDir("");
??????????????ret = obj.VerifyPin(userPin);
??????????????ret = obj.Execute(fileID, inBuff, outBuff);
??????????????ret = obj.Close();
???????} catch (e) {
??????????????alert("JS Exception: " + e.message);
???????}
??????
???????// JS数组操作,打印结果
???????var str = "";
???????for (var i = 0; i < outBuff.length; i++)
??????????????str += " " + outBuff[i];
???????alert(str);
?
4.??????????ActiveX代码
SENSE4_CONTEXT??g_ctx = {0};?//全局变量保存当前打开的ctx
?
//?打开设备,以设备ID作为筛选条件,若设备ID指定为空串,则打开第一把锁
STDMETHODIMP CS4ActiveX::OpenLock(BSTR deviceID, LONG* retVal)
{
?????????SENSE4_CONTEXT *?????????pctx??=???????NULL;
?????????unsigned?long????????????????ret??????????????=???????0;
?????????unsigned?long????????????????size???=???????0;
?????????unsigned?long????????????????devCount= 0;
?????????unsigned?long????????????????i??????????????????=???????0;
?????????char???????????????????????????????bDeviceID[9]??????= {0};
?????????char???????????????????????????????bUserPin[9]??????????????????= {0};
?
?????????S4Enum(NULL, &size);
?????????if?(size == 0)
?????????{
???????????????????*retVal = S4_NO_LIST;
???????????????????goto?cleanup;
?????????}
?????????pctx = (SENSE4_CONTEXT*) malloc(size);
?????????ret = S4Enum(pctx, &size);
?????????if?(ret != S4_SUCCESS)
?????????{
???????????????????*retVal = ret;
???????????????????goto?cleanup;
?????????}
?
?????????//?获取ascii格式的设备ID
?????????WideCharToMultiByte(CP_ACP, 0, deviceID, SysStringLen(deviceID), bDeviceID, 9, NULL, NULL);
?????????//?遍历,寻找deviceID为指定值的设备
?????????devCount = size /?sizeof(SENSE4_CONTEXT);
?????????for?(i = 0; i < devCount; i++)
?????????{
???????????????????if?(strlen(bDeviceID) == 0)?//?未指定设备ID,返回第一把锁
???????????????????{
????????????????????????????break;
???????????????????}
???????????????????if?(0 == memcmp(bDeviceID, pctx[i].bID, 8))
???????????????????{
????????????????????????????break;
???????????????????}
?????????}
?????????//?没有找到
?????????if?(i == devCount)
?????????{
???????????????????*retVal = S4_NO_LIST;
???????????????????goto?cleanup;
?????????}
????????
?????????memcpy(&g_ctx, &pctx[i],?sizeof(SENSE4_CONTEXT));
?
?????????ret = S4Open(&g_ctx);
?????????if?(ret != S4_SUCCESS)
?????????{
???????????????????*retVal = ret;
???????????????????goto?cleanup;
?????????}
?
?????????*retVal = S4_SUCCESS;
cleanup:
?????????if?(pctx)
?????????{
???????????????????free(pctx);
???????????????????pctx = NULL;
?????????}
?????????return?S_OK;
}
?
STDMETHODIMP CS4ActiveX::ChangeDir(BSTR dir, LONG* retVal)
{
?????????char????????????bDir[20]?????= {0};
?
?????????WideCharToMultiByte(CP_ACP, 0, dir, SysStringLen(dir), bDir, 20, NULL, NULL);
?????????*retVal = S4ChangeDir(&g_ctx, bDir);
?????????return?S_OK;
}
?
STDMETHODIMP CS4ActiveX::Execute(BSTR fileID, VARIANT inBuff, VARIANT outBuf, LONG* retVal)
{
?????????char????????????bFileID[5]??=???????{0};
?????????BYTE *???????????????bInBuff???????????????=???????NULL;
?????????BYTE *???????????????bOutBuff???=???????NULL;
?????????int????????????????????????inBuffSize??=???????0;
?????????int????????????????????????outBuffSize =?????0;
?????????unsigned?long?size??????????????????=???????0;
?????????unsigned?long?ret??????????=???????0;
?????????int????????????????????????i???????????????????????????=???????0;
?????????int????????????????????????tmp?????????????????????=???????0;
?
?????????GetArrayLength(inBuff.pdispVal, &inBuffSize);
?????????GetArrayLength(outBuf.pdispVal, &outBuffSize);
?
?????????if?(inBuffSize > 0)
???????????????????bInBuff = (BYTE*) malloc(inBuffSize);
?????????if?(outBuffSize > 0)
???????????????????bOutBuff = (BYTE*) malloc(outBuffSize);
?
?????????for?(i = 0; i < inBuffSize; i++)
?????????{
???????????????????GetArrayNumberOfIndex(inBuff.pdispVal, i, &tmp);
???????????????????bInBuff[i] = (BYTE)tmp;
?????????}
?
?????????WideCharToMultiByte(CP_ACP, 0, fileID, SysStringLen(fileID), bFileID, 5, NULL, NULL);
?????????ret = S4Execute(&g_ctx, bFileID, bInBuff, inBuffSize, bOutBuff, outBuffSize, &size);
?????????if?(ret != S4_SUCCESS)
?????????{
???????????????????*retVal = ret;
???????????????????return?S_FALSE;
?????????}
?
?????????for?(i = 0; i < size; i++)
?????????{
???????????????????SetArrayNumberOfIndex(outBuf.pdispVal, i, bOutBuff[i]);
?????????}
???????
?????????return?S_OK;
}
?
STDMETHODIMP CS4ActiveX::VerifyPin(BSTR userPin, LONG* retVal)
{
?????????unsigned?char??????bUserPin[9] = {0};
?????????WideCharToMultiByte(CP_ACP, 0, userPin, SysStringLen(userPin), (char*)bUserPin, 9, NULL, NULL);
?????????*retVal = S4VerifyPin(&g_ctx, bUserPin, 8, S4_USER_PIN);
?????????return?S_OK;
}
?
STDMETHODIMP CS4ActiveX::Close(LONG* retVal)
{
?????????*retVal = S4Close(&g_ctx);
?????????return?S_OK;
}
至此,本篇博文连载完成,希望您通过阅读此系列博文后,可以了解如何在JavaScript以及Acticex之间相互传递数据的问题,当然,也希望您与我们进行互动,能够在此基础之上,再发掘出更好的方法!!!