SAFEARRAY使用实例

原文地址:http://www.chinaitpower.com/A200507/2005-07-27/168883.html

目录:

SAFEARRAY使用实例... 1

目录:... 1

前言:... 1

何谓SAFEARRAY... 1

创建SAFEARRAY: 2

方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组... 2

方法二:使用SafeArrayAllocDescriptorSafeArrayAllocData在堆上创建一维数组... 2

方法三:使用SafeArrayAllocDescriptorSafeArrayAllocData在堆上创建二维数组... 3

方法四:使用SafeArrayCreate在堆上创建一维数组... 4

方法五:使用SafeArrayCreate在堆上创建二维数组... 5

方法六:使用SafeArrayCreateEx创建包含结构的一维数组... 5

访问SAFEARRAY: 7

方法一:使用SafeArrayAccessData方法... 7

方法二:使用SafeArrayGetElementSafeArrayPutElement 7

组件/客户中传递SAFEARRAY的原则:... 8

 

前言:

SAFEARRAY使用总是困扰很多人,为了把这个问题说个明白,我把我目前掌握的知识做个总结

 

何谓SAFEARRAY

SAFEARRAY实际上是一个结构,关于这部分可以参考MSDN

ms-help://MS.MSDNQTR.2003FEB.2052/automat/htm/chap7_9ntx.htm

我们不需要关心16位操作系统下的定义,因为我们团队只在WIN2000以上平台下开发。

 

创建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:

方法一:使用SafeArrayAccessData方法

这种方法可以参见创建SAFEARRAY之方法一

请注意,访问完后要调用SafeArrayUnaccessData方法,并且调用SafeArrayDestroy销毁数组

这种方式通常用于访问一位数组

方法二:使用SafeArrayGetElementSafeArrayPutElement

这种方法可以参见创建SAFEARRAY之方法五

这种方式在访问多维数组的时候很有用

组件/客户中传递SAFEARRAY的原则:

1)  在堆上创建SAFEARRAY数组

2)  一方创建,一方回收

3)  接收方不可以修改SAFEARRAY的数据,只能读或者销毁

在C#中,创建一个安全数组(SafeArray)作为COM接口的参数,需要使用到.NET框架提供的COM互操作性特性。SafeArray是一个在COM中用于存储数组数据的结构,它可以包含不同类型的元素,并且具有内存管理功能,确保在COM环境中传递时不会发生内存泄漏。 要在C#中创建SafeArray,通常需要引入`System.Runtime.InteropServices`命名空间,然后使用对应的属性和类型。下面是一个简单的例子,展示如何创建一个SafeArray并作为COM接口的方法参数: ```csharp using System; using System.Runtime.InteropServices; class Program { // 假设有一个COM方法,需要一个SafeArray作为参数 [DllImport("YourComLibrary.dll", PreserveSig = false)] private static extern void YourComMethod([In, Out] IntPtr pArray); // 创建一个SafeArray并将其指针传递给COM方法 static void Main() { // 创建一个空的SafeArray实例,这里以整型为例 int[] arrayElements = new int[10]; IntPtr pArray = CreateSafeArray(arrayElements); // 调用COM方法并传递SafeArray指针 YourComMethod(pArray); // 清理SafeArray资源 Marshal.DestroyStructure(pArray, typeof(SafeArrayBOUND)); for (int i = 0; i < arrayElements.Length; i++) { Marshal.DestroyStructure(Marshal.ReadIntPtr(pArray, i * IntPtr.Size), typeof(int)); } Marshal.FreeCoTaskMem(pArray); } // 定义创建SafeArray的方法 static IntPtr CreateSafeArray(int[] elements) { // 这里简化处理,实际应根据实际情况构造SafeArray结构 int length = Marshal.SizeOf(typeof(int)) * elements.Length; IntPtr pArray = Marshal.AllocCoTaskMem(length); // 填充SafeArray for (int i = 0; i < elements.Length; i++) { IntPtr pElement = new IntPtr(pArray.ToInt32() + i * Marshal.SizeOf(typeof(int))); Marshal.WriteInt32(pElement, elements[i]); } return pArray; } } ``` 请注意,上述代码是一个简化的示例,实际使用时需要根据具体的COM方法和SafeArray的类型进行相应的调整。创建SafeArray的具体实现可能会更加复杂,因为需要正确地设置SafeArray的边界和维数信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值