safearray的使用方法

安全数组可以存储多维数据。在标准C++表示中,可以定义这样的数组:long myArr[2][4]。在安全数组中,这种类型的数组就是2维(cDims)的。安全数组的每一维都有自己的SAFEARRAYBOUND结构,它由SAFEARRAY结构的rgsabound[]成员建立。每个SAFEARRAYBOUND定义了该维所含元素的数量和启始索引值。例如在数组 long myArray[2][4] 中,创建了两个SAFEARRAYBOUND结构,每一维都含有4个元素(cElements) 并且下限(lLbound)都为0。
虽然在VB中安全数组是以基于自然语言的数组形式提供的,但是C++程序员在处理安全数组时仍然需要使用专门的结构和辅助函数。下表是一些安全数组的辅助函数,他们用来创建、操作删除C++中的安全数组。其中 SafeArrayCreate(Ex) 和 SafeArrayDestroy 是最基本的两个函数。 SafeArrayCreateVector(Ex) 与 SafeArrayCreate(Ex)的不同之处在于前者只能用于创建一维数组。
函数    说明
SafeArrayAccessData    将锁计数器加1,并返回数组数据的指针。
SafeArrayAllocData    根据由SafeArrayallocDescriptor 创建的描述符号为一安全数组分配内存。
SafeArrayAllocDiscriptor(Ex)    为安全数组描述符分配内存。
SafeArrayCopy    复制已有的数组。
SafeArrayCopyData    在释放目标资源后将源数组复制到目标数组中。
SafeArrayCreate(Ex)    建立新的数组描述符。
SafeArrayCreateVector(Ex)    建立一个下标为0的一维数组。
SafeArrayDestroy    撤消一个数组描述符。
SafeArrayDestroyData    释放安全数组中的数据元素所使用的内存。
SafeArrayDestroyDescriptor    释放安全数组描述符所使用的内存。
SafeArrayGetDim    返回数组的维数。
SafeArrayGetElement    获得数组的某一元素。
SafeArrayGetElemsize    返回数组某一元素的大小。
SafeArrayGetLBound    获得数组给定维的下限。
SafeArrayGetUBound    获得数组给定维的上限。
SafeArrayLock    将数组锁计数器加1。
SafeArrayPtrOfIndex    返回一指向数组元素的指针。
SafeArrayPutElement    将一元素赋给数组。
SafeArrayRedim    更改数组大小。
SafeArrayUnaccessData    释放一个数组数据指针并将锁计数器减1。
SafeArrayUnlock    将锁计数器减1。
SafeArraySetRecordInfo    设置存储在给定安全数组中的RecordInfo。
SafeArrayGetRecordInfo    取出存储在给定安全数组中的RecordInfo。
SafeArraySetIID    设置给定安全数组接口的GUID值。
SafeArrayGetIID    取出给定安全数组接口的GUID值。
SafeArrayGetVartype    返回存储于给定安全数组中的类型。


下面的代码创建了一个二维安全数组,每一维包含4个 LONG 型数值:
// Create a SAFEARRAY of this type: long myArray[2][4];

SAFEARRAYBOUND pSab[2];
pSab[0].lLbound = 0;
pSab[0].cElements = 4;
pSab[1].lLbound = 0;
pSab[1].cElements = 4;

SAFEARRAY *pSa;
pSa = SafeArrayCreate(VT_I4, 2, pSab );
if( pSa == NULL )    cout << “SafeArrayCreat failed” << endl;

可以使用 SafeArrayGetElement 和 SafeArrayPutElement 函数对数组数据依次进行读写操作。例如,下面的代码段使用 SafeArrayPutElement 函数将数组中的一个元素赋值为3。

// long myArr[2][4];
// myArr[1][2] = 3;   //leftmost dimension first (the standard way )
    0    1    2    3
0    x    x    x    x
1    x    x    3    x

long index[2]={2,1}; // rightmost dimension first;
long data = 3;
SafeArrayPutElements(pSa, index, &data );

在SafeArrayPutElement 函数中需要注意的是如何指定所需元素。SafeArrayPutElement 的第二个变量是一指针,它指向数组各维的索引向量。最右边的一维(最低位)放在向量的最前(index[0]);最左边的一维(最低位)放在向量的最后(index[pSa->cDims-1])。由于在C++中对多维数组的访问正好与此相反,所以需要特别注意这点。你可以将一个二维数组想象成上面代码中所表示的展开的网络图案。
在 SafeArrayPutElement 与 SafeArrayGetElement 函数的明显的局限性在于它们每次只能处理一个数值,在处理大量安全数组的数据时会极大地降低性能。此时,可以选择使用函数SafeArrayAccessData 和 SafeArrayUnaccessData。SafeArrayAccessData 和 SafeArrayUnaccessData 将数组锁定在内存中,并返回指向该安全数组数据的指针,这样便可以直接访问安全数组中的数据。下面的代码段通过调用 SafeArrayAccessData 来直接获得数组中的数据。然后通过指针直接设置数组中的所有元素,之后调用 SafeArrayUnaccessData 对该数组解锁。随后调用 SafeArrayGetElement 函数从数组中取出一个元素以检验用指针直接进行访问是否成功。最后通过调用 SafeArrayDestroy 函数来释放该数组。

// Lock the array get a pointer to its data.
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);

// Now get one element by calling SafeArrayGetElement.
index[0] = 3;
index[1] = 1;
SafeArrayGetElement(pSa, index, &NewData);
cout << NewData << endl;        //Displays 11

// When finished, free the array.
SafeArrayDestroy(pSa);

若要在一个变量中存储安全数组,只需要简单地将变量类型成员(VARIANT.vt)与VT_ARRAY 标记进行或(OR)运算即可,如下所示:
VARIANT v1;
VariantInit(&v1);

v1.vt = VT_I4 | VT_ARRAY;      // Array of 4 byte integers
v1.parray = pSa;

用户自定义类型
过去,可以将数据结构传送给基于 v-table 接口的方法,但是这只适用于由MIDL编译器产生的 proxy/stub DLL调度的接口。而基于类型库调度的接口,如在 VB 或 JAVA 中定义的接口,由于类型库器程序无法处理这些复杂的类型,所以不能把结构作为方法参数类接受。后来,扩展了的类型库调度器可以支持用户自定义的类型(UDT)以及使用安全数组的UDT数组。要采用UDT作为方法的参数,需要先在IDL文件中定义该结构,然后用 MIDL来生成类型库。以下是在IDL中定义UDT的例子。注意,这里使用了 typedef IDL 关键字来给该结构赋予 GUID 值。

typedef [ uuid (10000099-0000-0000-0000-000000000001 ) ]
struct myDataType {
int x;
int y;
} myDataType;
也可以用变量类型把 UDT 作为参数传递给纯 IDispatch 接口。VT_RECORD 类型的变量封装了一个指向 RecordInfo 对象的指针,该对象包含有关 UDT 的必要信息。由系统提供的 RecordInfo 对象实现了 IRecordInfo 接口。 IRecordInfo 接口内容看 MSDN 的帮助。
IRecordInfo 接口能够使用变量类型把UDT 向基于 IDispatch 的接口传递。在运行的时候,可以通过调用 GetRecordInfoFromTypeInfo 或 GetRecordInfoFromGuids 函数来获得系统实现 IRecordInfo 接口的指针。GetRecordInfoFromTypeInfo 函数为类型信息中所描述的 UDT 搜索 RecordInfo 对象。以下的代码段首先载入类型库,再为 UDT 获得类型信息,然后调用 GetRecordInfoFromTypeInfo。
CComPtr < ITypeLib > spTypeLib;
LoadTypeLibEx(L”包含有类型库信息的文件”, REGKIND_DEFAULT, &spTypeLib);
if ( !spTypeLib )    return 0;

CComPtr < ITypeInfo > spTypeInfo;
spTypeLib->GetTypeInfoOfGuid(在IDL中指定的自定义类型的GUID, &spTypeInfo);
if( ! spTypeInfo )    return 0;

CComPtr < IRecordInfo > spRecordInfo;
GetRecordInfoFromTypeInfo( spTypeInfo, &spRecordInfo );
// 到这里,已经得到了 IRecordInfo 的接口指针。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值