ATL或COM如何处理JS传递的数组

最近碰到方正客户提出的一个问题,就是对于js定义的数组传递给我们的接口(ATL控件),值设置不进去,一直返回false。

经过查找原因,发现控件代码只处理了vb脚本类的数组,而js数组要特殊处理vbscript传进来的是个SafeArray。而javascript的情况就复杂了,javascript中得数组并不是真正意义上的数组,这个“数组”传到COM中被放进一个集合里,参数VARIANT的类型被置为VT_DISPATCH,我们得通过这个IDispatch指针调用invoke 才能得到用来读取集合的枚举接口。也就是说JS中的Array在COM中是一个实现了IDispatch的对象,可通过IDispatch接口api进行操作。

知道原因后就对接口实现做出如下调整:

首先定义两个辅助函数分别用来获取js数组的长度及指定index元素值

/***********************************************

书写人 :zhichao.wang

函数类型:辅助函数

函数名称:lcl_GetJSArrayLength

函数功能:获取Javascript数组中长度

返回值 :

***********************************************/

HRESULTCNsoControl::lcl_GetJSArrayLength(IDispatch* pDisp, int&pLength)

{

         BSTR varName = L"length";

         VARIANT varValue;

         DISPPARAMS noArgs = {NULL, NULL, 0, 0};

         DISPID dispId;

         HRESULT hr;

 

         hr = pDisp->GetIDsOfNames(IID_NULL,&varName, 1, LOCALE_USER_DEFAULT, &dispId);

         if(FAILED(hr))

                   returnhr;

         hr = pDisp->Invoke(dispId, IID_NULL,LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &varValue, NULL,NULL);

         if(SUCCEEDED(hr))

         {

                   pLength = varValue.intVal;

                   returnhr;

         }

         else

         {

                   returnhr;

         }

}

 

/***********************************************

书写人 :zhichao.wang

函数类型:辅助函数

函数名称:lcl_GetJSArrayLength

函数功能:获取Javascript数组中指定位置的元素值

返回值 :

***********************************************/

HRESULTCNsoControl::lcl_GetJSArrayDataOfIndex(IDispatch* pDisp, int index, VARIANT& pValue)

{

         CComVariant varName(index, VT_I4);   // 数组下标

         DISPPARAMS noArgs = {NULL, NULL, 0, 0};

         DISPID dispId;

         VARIANT varValue;

         HRESULT hr = 0;      

         varName.ChangeType(VT_BSTR);         // 将数组下标转为数字型,以进行GetIDsOfNames

         //

         // 获取通过下标访问数组的过程,将过程名保存在dispId中

         //

         hr = pDisp->GetIDsOfNames(IID_NULL,&varName.bstrVal, 1, LOCALE_USER_DEFAULT, &dispId);

         if(FAILED(hr))

                     return hr;

         //

         // 调用COM过程,访问指定下标数组元素,根据dispId 将元素值保存在varValue中

         //

         hr = pDisp->Invoke(dispId, IID_NULL,LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,&noArgs, &varValue, NULL,NULL);

         if(SUCCEEDED(hr))

         {

                    pValue = varValue;   

                    return hr;

         }

         else

         {

                     return hr;

         }

}

 

然后在对应的接口中做如下处理:

STDMETHODIMPCNsoControl::SetCompoundBoxCodeAndValueByArray(BSTR sName,VARIANTlstCode,VARIANT lstValue,int iType,VARIANT_BOOL*pVal)

{

         *pVal = VARIANT_FALSE;

         HRESULT hr;

         **************此处省略若干业务相关代码************************

         if(      lstCode.vt == VT_DISPATCH &&lstValue.vt == VT_DISPATCH )//处理JS数组

         {

                   //MessageBox(L"BeginToSetNo1");

                   intiCodeLen,iValueLen;

                   lcl_GetJSArrayLength(lstCode.pdispVal,iCodeLen);

                   lcl_GetJSArrayLength(lstValue.pdispVal,iValueLen);

                   VARIANT vCode,vValue;

                   for(int i=0;i<iCodeLen;i++ )

                   {

                            lcl_GetJSArrayDataOfIndex(lstCode.pdispVal,i,vCode);

                            lcl_GetJSArrayDataOfIndex(lstValue.pdispVal,i,vValue);

                            vParam[1] =CComVariant(vCode.bstrVal);

                            vParam[0] =CComVariant(vValue.bstrVal);

 

                            **************此处省略若干业务相关代码************************

                   }

                   *pVal = VARIANT_TRUE;

         }

         else//处理VB数组等

         {

                   if((lstCode.vt^VT_ARRAY) <1 || (lstCode.vt^VT_ARRAY)>73)//用户传入数组类型不正确直接返回

                            return S_OK;

                   if((lstValue.vt^VT_ARRAY) <1 || (lstValue.vt^VT_ARRAY)>73)//用户传入数组类型不正确直接返回

                            return S_OK;

                   try

                   {

                            long dim1=SafeArrayGetDim(lstCode.parray);

                            long dim2=SafeArrayGetDim(lstValue.parray);

                            long  ubound;

                            long  lbound;

                           

                            SafeArrayGetUBound(lstCode.parray,dim1,&ubound);

                            SafeArrayGetLBound(lstCode.parray,dim1,&lbound);

                           

                            BSTR*  buf1,*buf2;

                            SafeArrayAccessData(lstCode.parray,(void**)&buf1);

                            SafeArrayAccessData(lstValue.parray,(void**)&buf2);

                                    

                            for(int  i=lbound;i<ubound-lbound+1;i++)

                            {

                                     vParam[1] =CComVariant(buf1[i]);

                                     vParam[0] =CComVariant(buf2[i]);

                            **************此处省略若干业务相关代码************************

                            }

                            SafeArrayUnaccessData(lstCode.parray);// slove  the delphiproblem "variant or safe array is locked"

                            SafeArrayUnaccessData(lstValue.parray);

                            *pVal =VARIANT_TRUE;

                   }

                   catch(...)

                   {

                            *pVal =VARIANT_FALSE;

                            return S_OK;

                   }

         }

         returnS_OK;

}

 

经过修改后,对于js或其他语言传递的数组该接口都可以正确运行


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值