把javascript,vbscript中得数组传递给COM组件(or Activex)
2008-03-18 09:47
281 查看
COM组件的方法在IDL中的声明:
[id(1), helpstring("方法InputArray")] HRESULT InputArray([in] VARIANT vData);
在脚本中建立数组并调用COM组件的方法:
当数组很大的时候,like 100k ,javascript在给数组赋值的时候效率非常低!完成时间,cpu占用率,占用的内存都大的可怕。反而VBScript却完成的很好。
测试页面:
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">
<TITLE>对象 BigParamCtl 的 ATL 7.0 测试页</TITLE>
</HEAD>
<BODY>
<OBJECT id="BigParamCtl" data="data:application/x-oleobject;base64,G2I3cgi4DEazi5wM0glIGRAHAADYEwAA2BMAAA=="
classid="CLSID:7237621B-B808-460C-B38B-9C0CD2094819" >
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
Sub InputArray_VBScript
On Error Resume Next
Set BigParamCtla = CreateObject("BigParam.BigParamCtl")
if err<>0 then
Alert("BigParam not properly installed on this PC!")
else
Dim i
Dim a(10)
For i = 0 To 10
a(i) = asc("0")
Next
MsgBox("vbscript complete")
BigParamCtla.InputArray a
end if
End Sub
</SCRIPT>
<SCRIPT language="javascript">
function InputArray_javascript()
{
var a = new Array(10);
for(var i = 0; i < 10; i++)
{
a[i] = 49 ;
}
alert("javascript complete");
BigParamCtl.InputArray(a);
}
</SCRIPT>
<form name="form1" method="post" action="" ID="Form1">
<p>
Ret <input type="text" name="Ret" value="" ID="Text1"> <input type="button" name="Button" value="InputArray_VBScript" onclick="InputArray_VBScript"
ID="Button1">
</p>
<p>
Ret <input type="text" name="Ret" value="" ID="Text2"> <input type="button" name="Button" value="InputArray_javascript" onclick="InputArray_javascript"
ID="Button2">
</p>
</form>
</BODY>
</HTML>
?Sub InputArray_VBScript
?
??On Error Resume Next
??Set BigParamCtla = CreateObject("BigParam.BigParamCtl")
??if err<>0 then
???Alert("BigParam not properly installed on this PC!")
??else
???Dim i
???Dim a(10)
???For i = 0 To 10
????a(i) = asc("0")
???Next
???MsgBox("vbscript complete")????
???BigParamCtla.InputArray a
???????? end if
?End Sub
???
?function InputArray_javascript()
?{
??var a = new Array(10);
??for(var i = 0; i < 10; i++)
??{
???a[i] = 49 ;
??}
??alert("javascript complete");
??BigParamCtl.InputArray(a);
?}
COM组件的代码:
从代码中可以看到vbscript传进来的是个SafeArray。而javascript的情况就复杂了,javascript中得数组并不是真正意义上的数组,这个“数组”传到COM中被放进一个集合里,参数VARIANT的类型被置为VT_DISPATCH,我们得通过这个IDispatch指针调用invoke才能得到用来读取集合的枚举接口。
STDMETHODIMP CBigParamCtl::InputArray(VARIANT vData)
{
LPBYTE p ;
DWORD nLen;
HRESULT hr;
if( vData.vt == VT_DISPATCH)
{
//deal with javascript array
hr = VariantEnumToBytes(vData.pdispVal,&p, &nLen);
}
else
{
//deal with vbscript array
hr = VariantArrayToBytes(&vData, &p, &nLen) ;
}
if( S_OK == hr)
{
//....... do sth on p
delete[] p;
}
return S_OK;
}
HRESULT VariantEnumToBytes(IDispatch* disp, LPBYTE *ppBytes, DWORD *pdwBytes)
{
// DebugBreak();
HRESULT hr;
DISPPARAMS noArgs = { NULL, NULL, 0, 0 };
CComVariant resultV;
hr = disp->Invoke( DISPID_NEWENUM,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET,
&noArgs,
&resultV,
NULL,
NULL );
if( FAILED( hr ) && FAILED( resultV.ChangeType( VT_UNKNOWN ) ) )
return E_FAIL;
// Bug 37459, above Invoke succeeds, but returns resultV.vt == VT_EMPTY, resultV->other param unchanged
if (resultV.vt != VT_UNKNOWN && resultV.vt != VT_DISPATCH)
{
return E_FAIL;
}
CComQIPtr<IEnumVARIANT> pEnum( resultV.punkVal );
if( !pEnum )
return E_FAIL;
// Count the elements
*pdwBytes = 0;
hr = S_OK;
//Get Enum Size
while( hr == S_OK )
{
hr = pEnum->Skip(1);
if( hr == S_OK )
(*pdwBytes)++;
}
//allocate memory
*ppBytes = (LPBYTE)new BYTE[*pdwBytes];
int nCount = 0;
CComVariant elemV;
pEnum->Reset();
hr = S_OK;
while( hr == S_OK )
{
// Could switch to use Skip when Cary gets
// it working.
hr = pEnum->Next( 1, &elemV, NULL );
if( elemV.vt != VT_I4 )
hr = S_FALSE; // correct for dispproxy bug 19307
else
{
int nTmp = elemV.lVal;
(*ppBytes)[nCount] = (BYTE)nTmp;
}
if( hr == S_OK )
nCount++;
}
return S_OK;
}
HRESULT VariantArrayToBytes(VARIANT *pVariant, LPBYTE *ppBytes, DWORD *pdwBytes)
{
USES_CONVERSION;
if (pVariant->vt != (VT_VARIANT | VT_BYREF))
return E_INVALIDARG;
if (!(pVariant->pvarVal->vt & VT_ARRAY))
return E_INVALIDARG;
SAFEARRAY* pX = NULL;
if (pVariant->pvarVal->vt & VT_BYREF)
pX = *(pVariant->pvarVal->pparray);
else
pX = pVariant->pvarVal->parray;
if (::SafeArrayGetDim(pX) != 1)
return E_INVALIDARG;
*ppBytes = NULL;
*pdwBytes = 0;
VARIANT *pArray = NULL;
HRESULT hr = E_FAIL;
_variant_t v;
hr = SafeArrayAccessData(pX, (void **) &pArray );
if( SUCCEEDED(hr))
{
*pdwBytes = pX->rgsabound->cElements;
*ppBytes = (LPBYTE)new BYTE[*pdwBytes];
for( DWORD i = 0; i < *pdwBytes; i++)
{
v = pArray[i];
v.ChangeType(VT_UI1);
(*ppBytes)[i] = v.bVal;
}
SafeArrayUnaccessData( pX );
}
else
return hr;
SafeArrayDestroy(pX);
return S_OK;
}
[id(1), helpstring("方法InputArray")] HRESULT InputArray([in] VARIANT vData);
在脚本中建立数组并调用COM组件的方法:
当数组很大的时候,like 100k ,javascript在给数组赋值的时候效率非常低!完成时间,cpu占用率,占用的内存都大的可怕。反而VBScript却完成的很好。
测试页面:
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">
<TITLE>对象 BigParamCtl 的 ATL 7.0 测试页</TITLE>
</HEAD>
<BODY>
<OBJECT id="BigParamCtl" data="data:application/x-oleobject;base64,G2I3cgi4DEazi5wM0glIGRAHAADYEwAA2BMAAA=="
classid="CLSID:7237621B-B808-460C-B38B-9C0CD2094819" >
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
Sub InputArray_VBScript
On Error Resume Next
Set BigParamCtla = CreateObject("BigParam.BigParamCtl")
if err<>0 then
Alert("BigParam not properly installed on this PC!")
else
Dim i
Dim a(10)
For i = 0 To 10
a(i) = asc("0")
Next
MsgBox("vbscript complete")
BigParamCtla.InputArray a
end if
End Sub
</SCRIPT>
<SCRIPT language="javascript">
function InputArray_javascript()
{
var a = new Array(10);
for(var i = 0; i < 10; i++)
{
a[i] = 49 ;
}
alert("javascript complete");
BigParamCtl.InputArray(a);
}
</SCRIPT>
<form name="form1" method="post" action="" ID="Form1">
<p>
Ret <input type="text" name="Ret" value="" ID="Text1"> <input type="button" name="Button" value="InputArray_VBScript" onclick="InputArray_VBScript"
ID="Button1">
</p>
<p>
Ret <input type="text" name="Ret" value="" ID="Text2"> <input type="button" name="Button" value="InputArray_javascript" onclick="InputArray_javascript"
ID="Button2">
</p>
</form>
</BODY>
</HTML>
?Sub InputArray_VBScript
?
??On Error Resume Next
??Set BigParamCtla = CreateObject("BigParam.BigParamCtl")
??if err<>0 then
???Alert("BigParam not properly installed on this PC!")
??else
???Dim i
???Dim a(10)
???For i = 0 To 10
????a(i) = asc("0")
???Next
???MsgBox("vbscript complete")????
???BigParamCtla.InputArray a
???????? end if
?End Sub
???
?function InputArray_javascript()
?{
??var a = new Array(10);
??for(var i = 0; i < 10; i++)
??{
???a[i] = 49 ;
??}
??alert("javascript complete");
??BigParamCtl.InputArray(a);
?}
COM组件的代码:
从代码中可以看到vbscript传进来的是个SafeArray。而javascript的情况就复杂了,javascript中得数组并不是真正意义上的数组,这个“数组”传到COM中被放进一个集合里,参数VARIANT的类型被置为VT_DISPATCH,我们得通过这个IDispatch指针调用invoke才能得到用来读取集合的枚举接口。
STDMETHODIMP CBigParamCtl::InputArray(VARIANT vData)
{
LPBYTE p ;
DWORD nLen;
HRESULT hr;
if( vData.vt == VT_DISPATCH)
{
//deal with javascript array
hr = VariantEnumToBytes(vData.pdispVal,&p, &nLen);
}
else
{
//deal with vbscript array
hr = VariantArrayToBytes(&vData, &p, &nLen) ;
}
if( S_OK == hr)
{
//....... do sth on p
delete[] p;
}
return S_OK;
}
HRESULT VariantEnumToBytes(IDispatch* disp, LPBYTE *ppBytes, DWORD *pdwBytes)
{
// DebugBreak();
HRESULT hr;
DISPPARAMS noArgs = { NULL, NULL, 0, 0 };
CComVariant resultV;
hr = disp->Invoke( DISPID_NEWENUM,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET,
&noArgs,
&resultV,
NULL,
NULL );
if( FAILED( hr ) && FAILED( resultV.ChangeType( VT_UNKNOWN ) ) )
return E_FAIL;
// Bug 37459, above Invoke succeeds, but returns resultV.vt == VT_EMPTY, resultV->other param unchanged
if (resultV.vt != VT_UNKNOWN && resultV.vt != VT_DISPATCH)
{
return E_FAIL;
}
CComQIPtr<IEnumVARIANT> pEnum( resultV.punkVal );
if( !pEnum )
return E_FAIL;
// Count the elements
*pdwBytes = 0;
hr = S_OK;
//Get Enum Size
while( hr == S_OK )
{
hr = pEnum->Skip(1);
if( hr == S_OK )
(*pdwBytes)++;
}
//allocate memory
*ppBytes = (LPBYTE)new BYTE[*pdwBytes];
int nCount = 0;
CComVariant elemV;
pEnum->Reset();
hr = S_OK;
while( hr == S_OK )
{
// Could switch to use Skip when Cary gets
// it working.
hr = pEnum->Next( 1, &elemV, NULL );
if( elemV.vt != VT_I4 )
hr = S_FALSE; // correct for dispproxy bug 19307
else
{
int nTmp = elemV.lVal;
(*ppBytes)[nCount] = (BYTE)nTmp;
}
if( hr == S_OK )
nCount++;
}
return S_OK;
}
HRESULT VariantArrayToBytes(VARIANT *pVariant, LPBYTE *ppBytes, DWORD *pdwBytes)
{
USES_CONVERSION;
if (pVariant->vt != (VT_VARIANT | VT_BYREF))
return E_INVALIDARG;
if (!(pVariant->pvarVal->vt & VT_ARRAY))
return E_INVALIDARG;
SAFEARRAY* pX = NULL;
if (pVariant->pvarVal->vt & VT_BYREF)
pX = *(pVariant->pvarVal->pparray);
else
pX = pVariant->pvarVal->parray;
if (::SafeArrayGetDim(pX) != 1)
return E_INVALIDARG;
*ppBytes = NULL;
*pdwBytes = 0;
VARIANT *pArray = NULL;
HRESULT hr = E_FAIL;
_variant_t v;
hr = SafeArrayAccessData(pX, (void **) &pArray );
if( SUCCEEDED(hr))
{
*pdwBytes = pX->rgsabound->cElements;
*ppBytes = (LPBYTE)new BYTE[*pdwBytes];
for( DWORD i = 0; i < *pdwBytes; i++)
{
v = pArray[i];
v.ChangeType(VT_UI1);
(*ppBytes)[i] = v.bVal;
}
SafeArrayUnaccessData( pX );
}
else
return hr;
SafeArrayDestroy(pX);
return S_OK;
}
相关文章推荐
- 把javascript,vbscript中得数组传递给COM组件(or Activex)
- 把javascript,vbscript中得数组传递给COM组件(or Activex)
- 把javascript,vbscript中得数组传递给COM组件(or Activex)
- 把javascript,vbscript中得数组传递给COM组件(or Act
- 服务端vbscript与客户端javascript传递变量
- php和javascript交互:传递数组
- php和javascript交互:传递数组
- php实现向javascript传递数组的方法
- vbscript与javascript传递变量
- Javascript数组中的按值传递
- PHP和JavaScript传递数组并使用dtree.js生成树
- COM组件开发笔记--字符串数组的传递
- COM组件开发笔记--字符串数组的传递
- COM组件开发笔记--字符串数组的传递
- 关于vbscript 与 javascript如何传递变量(包括服务器端与客户端)
- JavaScript中运用VBScript获得的数组
- Javascript小知识点(七):数据类型赋值,浅拷贝,深拷贝(数组值传递还是引用传递)
- 如何将php数组或者对象传递给javascript
- 如何从ActiveX控件向JavaScript传递数组
- php向javascript传递数组