想建立利用VC6.0和ATL建立一个Activex控件,接收VBscript脚本中传递进来的数组元素值作为坐标显示直线,试验中参考了http://blog.csdn.net/leechy/archive/2004/07/01/31773.aspx,利用VC的variant数据类型接收vbscript的safearray,但试验中老是出错,代码及错误如下: 首先利用Atl Com AppWizard建立ATL工程,然后利用Insert-->New Atl Object建立控件类,选择Control-->Full Control按照默认选项来建立Activex控件类。为接口IDrawLine添加属性(IDL接口定义文件中属性定义)如下: [propput, id(3), helpstring("property InPutVbArray")] HRESULT InPutVbArray([in] VARIANT newVal); 建立控件类CDrawLine的数组成员,利用接口方法(属性)接收脚本传来的数组: int * m_VbIntArray; 在类构造函数中初始化该成员: m_VbIntArray=new int[2];
m_VbIntArray[0]=100;
m_VbIntArray[1]=100; CdrawLine的OnDraw方法内容如下: HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom); SetTextColor(di.hdcDraw,RGB(0,255,255)); SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("ATL 3.0 : DrawLine");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText)); HPEN hPen,hPenOld;
hPen = CreatePen( PS_SOLID, 1, RGB(0,255,255) );
hPenOld = (HPEN) SelectObject( di.hdcDraw, &hPen);
MoveToEx(di.hdcDraw,rc.left+m_VbIntArray[0], rc.bottom-m_VbIntArray[1], 0 );
LineTo( di.hdcDraw,rc.right, rc.top );
SelectObject(di.hdcDraw, &hPenOld ); DeleteObject(hPen);
return S_OK;
} CDrawLine类中接口属性的输入方法及相关函数内容如下: STDMETHODIMP CDrawLine::put_InPutVbArray(VARIANT newVal)
{
// TODO: Add your implementation code here
LPBYTE p ;
DWORD nLen;
HRESULT hr;
hr = VariantArrayToBytes(&newVal, &p, &nLen) ;
if( E_INVALIDARG == hr)
{
m_VbIntArray[0]=0;
m_VbIntArray[1]=0;
}
if( S_OK == hr)
{
//....... do sth on p
for(int i=0;i<2;i++)
{
m_VbIntArray[i]=(int)p[i];
}
delete[] p;
}
return S_OK;
}HRESULT CDrawLine::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) != 2)
return E_INVALIDARG;*/ pX = pVariant->parray;
//pX = pVariant->pvarVal->parray;
//pX = *(pVariant->pvarVal->pparray); *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[0].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;
}CDrawLine::VariantArrayToBytes方法中注释掉的内容是因为不注释掉的话后面的部分根本不会执行,程序编译通过,使用html脚本测试:<OBJECT
classid="clsid:2E2BEB4E-530F-444B-A987-B151ACFB2499"
id="ActivexDemo"
>
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
<!--
dim a
a=Array(50,50)
//dim a()
//redim a(2)
//a(0)=50
//a(1)=50
//a(2)=50
ActivexDemo.InPutVbArray=a
-->
</SCRIPT>出现不同类型的错误,有兴趣可以试一下。后改变思路,修改和简化接口属性的输入方法如下:STDMETHODIMP CDrawLine::put_InPutVbArray(VARIANT newVal)
{
// TODO: Add your implementation code here
//deal with vbscript array
VARIANT* v=&newVal;
SAFEARRAY* pS = v->parray;
//SAFEARRAY* pS = v->pvarVal->parray;
//SAFEARRAY* pS = *(v->pvarVal->pparray);//error
unsigned int cdims;
//cdims = SafeArrayGetDim(pS);
cdims=pS->cDims;
if ( cdims == 1 & pS->rgsabound[0].cElements==4)
{
USES_CONVERSION;
long * pNum;
//SafeArrayAccessData(pS, (void**)&pNum); //SafeArrayLock(pS);
pNum=(long *)pS->pvData;
m_VbIntArray[0]=pNum[2];
m_VbIntArray[1]=pNum[2]; //SafeArrayUnlock(pS);
}
return S_OK;
}测试脚本如下:<OBJECT
classid="clsid:2E2BEB4E-530F-444B-A987-B151ACFB2499"
id="ActivexDemo"
>
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
<!--
ActivexDemo.Coordinate=50.0
dim a
a=Array(50,50,50,50)
ActivexDemo.InPutVbArray=a
-->
</SCRIPT>只能取到pNum[2]的值并划线,其它元素值都取不到。而且只能使用Array定义VBscript数组,另外一种定义方法也不行,到底是什么原因也不知道,请高手予以指点。
m_VbIntArray[0]=100;
m_VbIntArray[1]=100; CdrawLine的OnDraw方法内容如下: HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom); SetTextColor(di.hdcDraw,RGB(0,255,255)); SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("ATL 3.0 : DrawLine");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText)); HPEN hPen,hPenOld;
hPen = CreatePen( PS_SOLID, 1, RGB(0,255,255) );
hPenOld = (HPEN) SelectObject( di.hdcDraw, &hPen);
MoveToEx(di.hdcDraw,rc.left+m_VbIntArray[0], rc.bottom-m_VbIntArray[1], 0 );
LineTo( di.hdcDraw,rc.right, rc.top );
SelectObject(di.hdcDraw, &hPenOld ); DeleteObject(hPen);
return S_OK;
} CDrawLine类中接口属性的输入方法及相关函数内容如下: STDMETHODIMP CDrawLine::put_InPutVbArray(VARIANT newVal)
{
// TODO: Add your implementation code here
LPBYTE p ;
DWORD nLen;
HRESULT hr;
hr = VariantArrayToBytes(&newVal, &p, &nLen) ;
if( E_INVALIDARG == hr)
{
m_VbIntArray[0]=0;
m_VbIntArray[1]=0;
}
if( S_OK == hr)
{
//....... do sth on p
for(int i=0;i<2;i++)
{
m_VbIntArray[i]=(int)p[i];
}
delete[] p;
}
return S_OK;
}HRESULT CDrawLine::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) != 2)
return E_INVALIDARG;*/ pX = pVariant->parray;
//pX = pVariant->pvarVal->parray;
//pX = *(pVariant->pvarVal->pparray); *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[0].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;
}CDrawLine::VariantArrayToBytes方法中注释掉的内容是因为不注释掉的话后面的部分根本不会执行,程序编译通过,使用html脚本测试:<OBJECT
classid="clsid:2E2BEB4E-530F-444B-A987-B151ACFB2499"
id="ActivexDemo"
>
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
<!--
dim a
a=Array(50,50)
//dim a()
//redim a(2)
//a(0)=50
//a(1)=50
//a(2)=50
ActivexDemo.InPutVbArray=a
-->
</SCRIPT>出现不同类型的错误,有兴趣可以试一下。后改变思路,修改和简化接口属性的输入方法如下:STDMETHODIMP CDrawLine::put_InPutVbArray(VARIANT newVal)
{
// TODO: Add your implementation code here
//deal with vbscript array
VARIANT* v=&newVal;
SAFEARRAY* pS = v->parray;
//SAFEARRAY* pS = v->pvarVal->parray;
//SAFEARRAY* pS = *(v->pvarVal->pparray);//error
unsigned int cdims;
//cdims = SafeArrayGetDim(pS);
cdims=pS->cDims;
if ( cdims == 1 & pS->rgsabound[0].cElements==4)
{
USES_CONVERSION;
long * pNum;
//SafeArrayAccessData(pS, (void**)&pNum); //SafeArrayLock(pS);
pNum=(long *)pS->pvData;
m_VbIntArray[0]=pNum[2];
m_VbIntArray[1]=pNum[2]; //SafeArrayUnlock(pS);
}
return S_OK;
}测试脚本如下:<OBJECT
classid="clsid:2E2BEB4E-530F-444B-A987-B151ACFB2499"
id="ActivexDemo"
>
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
<!--
ActivexDemo.Coordinate=50.0
dim a
a=Array(50,50,50,50)
ActivexDemo.InPutVbArray=a
-->
</SCRIPT>只能取到pNum[2]的值并划线,其它元素值都取不到。而且只能使用Array定义VBscript数组,另外一种定义方法也不行,到底是什么原因也不知道,请高手予以指点。
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货