SAFEARRAY 和 CComSafeArray 的使用
SAFEARRAY是为了处理未知语言在COM客户之间传递数组的挑战,而定义的一个数组结构。跟VARIANT一样,SAFEARRAY也是自描述的通用数组。
SAFEARRAY的定义如下:
typedef struct tagSAFEARRAY
{
USHORT cDims; // 数组的维数
USHORT fFeatures;
ULONG cbElements;//每个元素的大小
ULONG cLocks;
PVOID pvData;
SAFEARRAYBOUND rgsabound[1]; //上下界指针数组
} SAFEARRAY;
SAFEARRAYBOUND 的定义如下:
typedef struct tagsSAFEARRAYBOUND
{
ULONG cElements; //当前维度的 元素个数
LONG lLbounds;// 下界,开始的下表,比如0
} SAFEARRAYBOUND;
数组最左边的维数保存在rgsbound[0]中,最右边的维数保存在rgsbound[cDims-1]中。
(1) 如何创建一个 SAFEARRAY ,SafeArrayCreate函数
第一个参数指定元素数据类型,第二个参数指定维数,第三个参数指定维数数组。
例如:创建一个c语言格式的 [3][4] 数组
SAFEARRAYBOUND rgsbound[2];
rgsbound[0].cElements=3;
rgsbound[0].lLbound=0;
rgsbound[1].cElements=4;
rgsbound[1].lLbound=0;
SAFEARRAY * psa= ::SafeArrayCreate(VT_I4,2, rgsbound);
(2) 如何获得一个元素 SafeArrayGetElement
第一个参数是SAFEARRAY指针,第二个参数是指定下标的数组,第三个参数返回指定元素的值。
注意第二个参数,下标数组的顺序是从右往左的,跟数组的创建顺序正好相反。
例如: 要获得[1][2]所在下标的位置
long rgIndices[]={2,1}; //注意不是 {1,2}
long lElem;
::SafeArrayGetElements(pas,rgIndices,(void *)&lElem);
(3) 释放销毁一个SAFEARRAY SafeArrayDestroy
SafeArrayDestroy(psa);
CComSafeArray
CComSafeArray是ATL对SAFEARRAY结构体的包装,是一个模板类。 SAFEARRAY只能够保存VARIANT内的那些数据一个子集。
(1)CComSafeArray的构造函数
(1.1) CComSafeArray(ULONG ulCount,LONG lLbound=0)
函数构造一个ulCount个元素的一维数组,下标从lLbound开始。
CComSafeArray<long> csa(10); //创建一个10个元素的以0为起始下标的一维数组 CComSafeArray<long> csa(10,0);//创建一个10个元素的以0为起始下标的一维数组 CComSafeArray<long> csa(10,1);//创建一个10个元素的以1为起始下标的一维数组
(1.2)CComSafeArray(const SAFEARRAYBOUND & bound,UINT uDims=1)
CComSafeArrayBound 被用来构建一个SAFEARRAYBOUND,它是从SAFEARRAYBOUND派生出来的包装类。所以可以用来替换SAFEARRAYBOUND。
例如:构建一个[2][3][4]数组
CComSafeArrayBound b1(2,0); CComSafeArrayBound b2(3,0); CComSafeArrayBound b3(4,0); CComSafeArrayBound rgBounds[]={b1,b2,b3}; CComSafeArray<int> sa(rgBounds, 3);
(1.3) CComSafeArray(const SAFEARRAY * psaSrc):m_psa(NULL);
CComSafeArray(const SAFEARRAY & psaSrc):m_psa(NULL);
CComSafeArray(const CComSafeArray & saSrc):m_psa(NULL);
(2) CComSafeArray的析构函数
析构函数就是调用内部SAFEARRAY的 SafeArrayDestroy函数。
(3) CComSafeArray的赋值
一个是接受SAFEARRAY 的赋值,一个是接受CComSafeArray的赋值。
在赋值之前,都会清除左边实例的内容,释放原先的资源。
(4) Detach和 Attach方法
Detach将所有权从CComSafeArray转移到SAFEARRAY,而Attach正好相反,Attach是将所以权从SAFEARRAY转移到CComSafeArray,这个跟CComVariant相似。
当我们在一个方法内部,获得从外面传递进来的SAFEARRAY的时候,采用下面的方法:
void SetArray(SAFEARRAY * psa) { CComSafeArray<long> sa; sa.Attach(psa); //操作 ..... sa.Detach(); }
当我们从一个方法来返回SAFEARRAY的时候,用下面的代码:
void GetArray(SAFEARRAY ** ppsa) { CComSafeArray <long> sa(10); *ppsa=sa.Detach(); }
(5) 如何获得和修改一维数组的元素
GetAt 和 SetAt CComSafeArray<long> sa(10); sa.SetAt(1,100);//将第2个元素设置为100 long value=sa.GetAt(2); //获得第3个元素的值,放入到value中。
(6) 如何获得和修改 多维数组的元素
MultiDimGetAt和 MultiDimSetAt
MultiDimGetAt(const LONG* index,T &t)
MultiDimSetAt(const LONG* index, cosnt T&t)
第一个参数是 一个LONG数组,指定访问元素下标,第二个参数是获得或者设置的元素值。
例子代码如下:
//创建一个 【3】【4】的2维数组 CComSafeArrayBound b1[3]; CComSafeArrayBound b2[4]; CComSafeArrayBound rg[]={b1,b2}; CComSafeArray<long> sa(rg,2); //获得【2】【1】元素的值 int rgIndexElementA[]={1,2}; long lVal sa.MultiDimGetAt(rgIndexElementA,lVal); //设置 【0】【1】元素的值为100 int rgIndexElementB[]={1,0}; long newVal=100; sa.MultiDimSetAt(rgIndexElementB,newVal);
(7) operator []操作符
【】操作符让我们能够像普通的数组那样来操作CComSafeArray对象,由于内部是
使用GetAt来实现,所以[]操作符只能准对一维数组对象,而不能准对多维数组对象。
实例代码如下:
CComSafeArray <int> sa(5); sa[2]=100;