WINDOWS-基础:SafeArray的使用方法
1 SafeArray的作用
- 使用SafeArray SafeArray是VB中的数组存储方式。通过SafeArray,可以在VC++和VB间相互调用。
- SafeArray也是Automation中的标准数组存储方式。SAFEARRAY的主要目的是用于automation中的数组型参数的传递。因为在网络环境中,数组是不能直接传递的,而必须将其包装成SafeArray。
- 实质上SafeArray就是将通常的数组增加一个描述符,说明其维数、长度、边界、元 素类型等信息。
- SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,然后才作为参数传送出去。
- 在VARIANT的vt成员的值如果包含VT_ARRAY|...,那么它所封装的就是一个SafeArray,它的parray成员即是指向SafeArray的指针。
- SafeArray中元素的类型可以是VARIANT能封装的任何类型,包括VARIANT类型本身。
将SafeArray包装到VARIANT变量中
SAFEARRAY *pSa; VARIANT v1; VariantInit(&v1); v1.vt = VT_I4 | VT_ARRAY; // Array of 4 byte integers v1.parray = pSa;
2 SafeArray结构体
typedef struct tagSAFEARRAY { unsigned short cDims;//维数 unsigned short fFeatures;// 用来描述数组如何分配和如何被释放的标志 unsigned long cbElements;// 数组元素的大小 unsigned long cLocks;// 一个计数器,用来跟踪该数组被锁定的次数 void * pvData;// 指向数据缓冲的指针 SAFEARRAYBOUND rgsabound[ 1 ];// 描述数组每维的数组结构,该数组的大小是可变的 } SAFEARRAY;
这个结构的成员(cDims,cLocks等)是通过API函数来设置和管理的。真正的数据存放在pvData成员中,而SAFEARRAYBOUND结构定义该数组结构的细节。以下就是该结构成员的简要描述:
rgsabound成员是一个SAFEARRAYBOUND结构的数组--每个元素代表SAFEARRAY的一个维。
typedef struct tagSAFEARRAYBOUND { unsigned long cElements;// 每维中元素的个数 unsigned long lLbound;// } SAFEARRAYBOUND;
例如C语言中的数组int a[3][4][5]用安全数组表示的时候则 cDims=3 ;cbElements=sizeof(int) 元素 cElements lLbound
rgsabound[0] 3 0
rgsabound[1] 4 0
rgsabound[2] 5 0
3 SafeArray的初始化方法
方法一 利用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建一维数组。 long nData[10]={1,2,3,4,5,6,7,8,9,10};//数据源
SAFEARRAY* pArray=NULL; HRESULT hr=SafeArrayAllocDescriptor(1,&pArray); HRESULT SafeArrayAllocDescriptor ( unsigned int cDims, SAFEARRAY FAR* FAR* ppsaOut ); 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);//维数索引从1开始 HRESULT SafeArrayGetLBound ( SAFEARRAY FAR* psa, unsigned int nDim, long FAR* plLbound ); SafeArrayGetUBound(pArray,1,&h); long Size=h-l+1; SafeArrayAccessData(pArray,(void**)&pData); for(long Idx=l;Idx<Size;++Idx) { } SafeArrayUnaccessData(pArray); pData[Idx]=nData[Idx];
方法二 用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建二维数组
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 Demen[2]; for(long i=0;i<3;++i) { for(long j=0;j<3;++j) { Demen[1]=i; } }
在SafeArrayPutElement 函数中需要注意的是如何指定所需元素。SafeArrayPutElement 的第二个变量是一指针,它指向数组各维的索引向量。最右边的一维(最低位)放在向量的最前(index[0]);最左边的一维(最低位)放在向量的最后(index【cDims-1]】)。由于在C++中对多维数组的访问正好与此相反,所以需要特别注意这点。
即用SafeArrayPutElement对二维SAFEARRAY数组使用的时候下标要注意, Demen[1]代表行,Demen[0]代表列。 Demen[0]=j; ong x=i*j; SafeArrayPutElement(pArray,Demen,&x);
访问二维数组
for(long i=0;i<3;++i) { for(long j=0;j<3;++j) { http://9455.net九九文章网 } Demen[1]=i; Demen[0]=j; long x(0); SafeArrayGetElement(pArray,Demen,&x); cout<<"("<<i<<","<<j<<") "<<x<<endl; } SafeArrayDestroy(pArray);
在 SafeArrayPutElement 与 SafeArrayGetElement 函数的明显的局限性在于它们每次只能处理一个数值,在处理大量安全数组的数据时会极大地降低性能。此时,可以选择使用函数SafeArrayAccessData 和 SafeArrayUnaccessData。SafeArrayAccessData 和 SafeArrayUnaccessData 将数组锁定在内存中,并返回指向该安全数组数据的指针,这样便可以直接访问安全数组中的数据
例如
SafeArray* psa long * pData; long * pData; SafeArrayAccessData(psa, (LPVOID *)&pData); // Set or get any values in the array. *pData = 4; *(pData + 1) = 5; *(pData + 2) = 6; *(pData + 3) = 7; *(pData + 4) = 8; *(pData + 5) = 9; *(pData + 6) =10; *(pData + 7) = 11; // Unlock the array.(pData is no longer valid.) SafeArrayUnaccessData(pSa); 然后进行如下操作 index[0] = 3; index[1] = 1; SafeArrayGetElement(pSa, index, &NewData); cout << NewData << endl;
则NewData的值为11
方法四:使用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) { } SafeArrayUnaccessData(pArray);
SafeArrayDestroy(pArray);
pData[Idx]=Idx;
cout<<pData[Idx]<<endl;
方法五:使用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) { } SafeArrayDestroy(pArray); 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;
根据MSDN中SafeArrayAllocDescriptor allows the creation of safe arrays that contain elements with data types other than those provided by After creating an array descriptor using SafeArrayAllocDescriptor, set the element