在COM中使用数组参数-SafeArray[转载/修改]

目录
何谓SAFEARRAY
创建SAFEARRAY
方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组
方法二:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建一维数组
方法三:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建二维数组
方法四:使用SafeArrayCreate在堆上创建一维数组
方法五:使用SafeArrayCreate在堆上创建二维数组
方法六:使用SafeArrayCreateEx创建包含结构的一维数组
访问SAFEARRAY:7
方法一:使用SafeArrayAccessData方法
方法二:使用SafeArrayGetElement和SafeArrayPutElemen
组件/客户中传递SAFEARRAY的原则
 
何谓SAFEARRAY
SAFEARRAY是一个结构,类型定义如下,具体可参考MSDN.
 
typedef struct tagSAFEARRAY
    {
       USHORT cDims;      //数组维数
       USHORT fFeatures; //数组的一些特性
       ULONG cbElements;//每一个元素的字节长度
       ULONG cLocks;      //锁定的字数
       PVOID pvData;      //具体数据
       SAFEARRAYBOUND rgsabound[ 1 ]; // 每一维的信息
    }  SAFEARRAY;
 
方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组
     //创建SAFEARRAY数组,每个元素为long型,该数组是一维数组
     long nData[10]={1,2,3,4,5,6,7,8,9,10};
 
     SAFEARRAY* pArray=NULL;
     HRESULT hr=SafeArrayAllocDescriptor(1,&pArray);//创建SAFEARRAY结构的对象
     pArray->cbElements=sizeof(nData[0]);    //长度应用为字节长度   
    pArray->rgsabound[0].cElements=10;    
     pArray->rgsabound[0].lLbound=0;
     pArray->pvData=nData;
     pArray->fFeatures=FADF_AUTO|FADF_FIXEDSIZE;
  //FADF_AUTO指定在栈上分配数据,并且大小不可以改变(固定为10)
    
     //访问SAFEARRAY数组
     long* pValue=NULL;
     SafeArrayAccessData(pArray,(void**)&pValue);
     long Low(0),High(0);
     hr=SafeArrayGetLBound(pArray,1,&Low);//维数索引从1开始
     hr=SafeArrayGetUBound(pArray,1,&High);//维数索引从1开始
 
     SafeArrayUnaccessData(pArray);
     SafeArrayDestroy(pArray);
  //这种方法释放在栈上分配数组元素所占的空间,即nData数组所用的空间 
 
方法二:使用SafeArrayAllocDescriptorSafeArrayAllocData在堆上创建一维数组
     //创建SAFEARRAY数组,每个元素为long型,该数组是一维数组
     long nData[10]={1,2,3,4,5,6,7,8,9,10};
 
     SAFEARRAY* pArray=NULL;
     HRESULT hr=SafeArrayAllocDescriptor(1,&pArray);//创建SAFEARRAY结构的对象
     pArray->cbElements=sizeof(nData[0]);
     pArray->rgsabound[0].cElements=10;
     pArray->rgsabound[0].lLbound=0;
     SafeArrayAllocData(pArray);
 
     long* pData=NULL;
     SafeArrayAccessData(pArray,(void**)&pData);
     long l(0),h(0);
     SafeArrayGetLBound(pArray,1,&l);
     SafeArrayGetUBound(pArray,1,&h);
     long Size=h-l+1;
     SafeArrayAccessData(pArray,(void**)&pData);
     for(long Idx=l;Idx<Size;++Idx)
     {
          pData[Idx]=nData[Idx];
     }
     SafeArrayUnaccessData(pArray);
 
     //访问SAFEARRAY数组
     long* pValue=NULL;
     SafeArrayAccessData(pArray,(void**)&pValue);
     long Low(0),High(0);
     hr=SafeArrayGetLBound(pArray,1,&Low);//维数索引从1开始
     hr=SafeArrayGetUBound(pArray,1,&High);//维数索引从1开始
 
     SafeArrayUnaccessData(pArray);
     SafeArrayDestroy(pArray);
 
 
方法三:使用SafeArrayAllocDescriptorSafeArrayAllocData在堆上创建二维数组
       SAFEARRAY* pArray=NULL;
     HRESULT hr=SafeArrayAllocDescriptor(2,&pArray);
     pArray->rgsabound[0].lLbound=0;
     pArray->rgsabound[0].cElements=3;
     pArray->rgsabound[1].lLbound=0;
     pArray->rgsabound[1].cElements=3;
 
     pArray->cbElements=sizeof(long);
     hr=SafeArrayAllocData(pArray);
 
     long lDimension[2];
     long x=1;
     //为第一行赋值
     for(long i=0;i<3;++i)
     {
          lDimension[1]=0;//行
          lDimension[0]=i;//列
          SafeArrayPutElement(pArray,lDimension,&x);
         x++;
     }
     //为第二行赋值
     for(long i=0;i<3;++i)
     {
          lDimension[1]=1;//行
          lDimension[0]=i;//列
          SafeArrayPutElement(pArray,lDimension,&x);
         x++;
     }
    
     //读取SafeArray中第二行第三列的数据
     long y(0);
     lDimension[1]=1;
     lDimension[0]=2;
     SafeArrayGetElement(pArray,lDimension,&y);
 
     SafeArrayDestroy(pArray);
 
二维SAFEARRAY数组使用的时候下标要注意,这里采用的是列主序的方式,即lDimension[1]代表行,lDimension[0]代表列。
 
 
 
方法四:使用SafeArrayCreate在堆上创建一维数组
     SAFEARRAYBOUND Bound[1];
     Bound[0].lLbound=0;
     Bound[0].cElements=10;
     SAFEARRAY* pArray=SafeArrayCreate(VT_I4,1,Bound);
     long* pData=NULL;
     HRESULT hr=SafeArrayAccessData(pArray,(void**)&pData);
     long Low(0),High(0);
     SafeArrayGetLBound(pArray,1,&Low);
     SafeArrayGetUBound(pArray,1,&High);
     long Size=High-Low+1;
     for(long Idx=Low;Idx<Size;++Idx)
     {
          pData[Idx]=Idx;
          cout<<pData[Idx]<<endl;
     }
     SafeArrayUnaccessData(pArray);
     SafeArrayDestroy(pArray);
 
方法五:使用SafeArrayCreate在堆上创建二维数组
     SAFEARRAYBOUND Bound[2];
     Bound[0].lLbound=0;
     Bound[0].cElements=3;
     Bound[1].lLbound=0;
     Bound[1].cElements=3;
     SAFEARRAY* pArray=SafeArrayCreate(VT_I4,2,Bound);
    
     long Demen[2];
     for(long i=0;i<3;++i)
     {
          for(long j=0;j<3;++j)
         {
              Demen[1]=i;
              Demen[0]=j;
              long x=i*j;
              SafeArrayPutElement(pArray,Demen,&x);
         }
     }
 
     //访问二维数组
     for(long i=0;i<3;++i)
     {
          for(long j=0;j<3;++j)
         {
              Demen[1]=i;
              Demen[0]=j;
              long x(0);
              SafeArrayGetElement(pArray,Demen,&x);
               cout<<"("<<i<<","<<j<<") "<<x<<endl;
         }
     }
     SafeArrayDestroy(pArray);
 
方法六:使用SafeArrayCreateEx创建包含结构的一维数组
使用SAFEARRAY传递UDT(自定义结构)是一项常用的技术,MSDN文档描述得比较齐全,要注意的一点是,自定义结构要求有自己的GUID,这必须在IDL文件中定义。同时还必须要使用IRecordInfo接口,该接口将和数组一起传递出去,IRecordInfo接口内部记录了UDT的描述信息。
IDL文件中:
[uuid(810930AA-9229-46e7-B20C-41F6218D0B1A)]
struct _BookMarkSchema
{
     BSTR Name;
     BSTR Context;
     BSTR Time;
};
 
interface IShape : IDispatch
{
[id(6), helpstring("获取属于某用户的书签名称列表")] HRESULT GetBookMarkName([in] BSTR UserID,[out] SAFEARRAY(struct _BookMarkSchema)* pBookMarkNames);
}
 
 
library SarstShapeLib
{
    
     importlib("stdole2.tlb");
     [
          uuid(DBDCC0F1-38F3-4EB4-A5BD-79A3707BDE9C),
          helpstring("Shape Class")
     ]
     coclass Shape
     {
          [default] interface IShape;
     };
     struct _BookMarkSchema;
};
 
 
方法的实现为:
STDMETHODIMP CShape::GetBookMarkName(BSTR UserID,SAFEARRAY** pBookMarkNames)
{
     //获得GIS库信息
     CSarstConfigure Configure;
     string Flag("GIS");
     string IP,Database,UserName,Key,Context;
     Configure.GetDatabaseInfo(Flag,IP,Database,UserName,Key,Context);
 
     //读取图层属性数据
     USES_CONVERSION;
     string user(CString(UserID).GetBuffer());
     string sql("SELECT 书签名,书签描述,时间 FROM 用户书签表 where 用户ID='"+user+"' order by 时间 desc");
     FBData data(IP,Database,UserName,Key);
     table t=data.GetTable(sql);
     if(t.empty())
     {
         return S_FALSE;
     }
     //创建SafeArray
     IRecordInfo* pRecordInfo=NULL;
     HRESULT hr=::GetRecordInfoFromGuids(LIBID_SarstShapeLib,1,0,GetUserDefaultLCID(),IID_STRUCT_BookMarkSchema,&pRecordInfo);
     if(FAILED(hr))
         return E_FAIL;
     *pBookMarkNames=::SafeArrayCreateVectorEx(VT_RECORD,0,long(t.size()-1),(void*)pRecordInfo);
     _BookMarkSchema* pData=NULL;
     hr=::SafeArrayAccessData(*pBookMarkNames,(void**)&pData);
     for(int i=0;i<int(t.size()-1);i++)
     {
          t[i+1].at(0).CopyTo(&pData[i].Name);
          t[i+1].at(1).CopyTo(&pData[i].Context);
          t[i+1].at(2).ChangeType(VT_BSTR);
          t[i+1].at(2).CopyTo(&pData[i].Time);
     }
     ::SafeArrayUnaccessData(*pBookMarkNames);
     pRecordInfo->Release();
     return S_OK;
}
访问SAFEARRAY:
这种方法可以参见创建SAFEARRAY之方法一
请注意,访问完后要调用SafeArrayUnaccessData方法,并且调用SafeArrayDestroy销毁数组
这种方式通常用于访问一位数组
这种方法可以参见创建SAFEARRAY之方法五
这种方式在访问多维数组的时候很有用
组件/客户中传递SAFEARRAY的原则:
1) 在堆上创建SAFEARRAY数组
2) 一方创建,一方回收
 
 
 
posted @ 2009-01-05 10:13  Christmas  阅读(2325)  评论(1编辑  收藏  举报