- GIS论坛-GIS空间站 ( http://bbs.gissky.net/Default.asp )
-- 编程技术交流 ( http://bbs.gissky.net/ShowForum.asp?forumid=22 )
--- vbscript传递数组到activex控件 ( http://bbs.gissky.net/ShowPost.asp?id=43576 )


作者:zcgumxh
发表时间:2008-4-1 11:42:32

     想建立利用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数组,另外一种定义方法也不行,到底是什么原因也不知道,请高手予以指点。

相关附件



Powered by GIS空间站 © 2002-2007