想建立利用VC6.0和ATL建立一个Activex控件,接收VBscript脚本中传递进来的数组元素值作为坐标显示直线,试验中参考了http:blog.csdn.netleechyarchiv
想建立利用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脚本测试:
《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;
}
测试脚本如下:
《SCRIPT》
只能取到pNum[2]的值并划线,其它元素值都取不到。而且只能使用Array定义Vbscript数组,另外一种定义方法也不行,到底是什么原因也不知道,请高手予以指点。
4 个解决方案
你可以把数组构造成一个字符串传给ActiveX控件.