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或其他語言傳遞的數組該接口都可以正確運行


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章