COM之VARIANT类型,以及SafeArray

VARIANT简介

在COM中,我们经常会碰到VARIANT这种类型,用于表示参数。它的别名有tagVARIANT,VARIANTARG

VARIANT是一个大的联合体,可以表示多种类型的参数。

重要成员

VARTYPE vt —— 表示这个VARIANT内部存储的变量类型。

然后就是对应的数据成员了。比如vt为VT_I8,那么对应的数据在llVal;比如vt为VT_R4,那么数据在fltVal中。

获取成员

使用V_VT宏,可以获取VARIANT数据的类型; 使用V_R4()可以获取float型的数据;使用V_ARRAY,可以获取parray数据;

参考:https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant

CComVariant简介

在活动模板库ATL中引入了智能VARIANT类型,就是CComVariant,别名为CComVariantImpl。它是继承于VARIANT的。封装了不同的类型入参的构造函数,以及赋值操作符,和内部的引用计数维护,BSTR字符串维护。

我们可以尽量用这个类型,来避免内存泄漏。

背景

现在项目碰到一个需求,需要用VARIANT传递一个数组,就是vt为 VT_ARRAY, 数据在 SAFEARRAY* parray 中。

使用VARIANT表示VARIANT数组

代码

SAFEARRAYBOUND abound;
abound.cElements = 5;
abound.lLbound = 0;

SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &abound);
VARIANT* pVar;
SafeArrayAccessData(psa, (void**)&pVar);
// 访问数据操作
SafeArrayUnaccessData(psa);
// 释放内部数据
SafeArrayDestroy(psa);

SAFEARRAY结构

这个结构通常是我们通过SafeArrayCreate调用返回的,不需要我们指定。

cDims —— 数组的维度,因为我们可以用SAFEARRAY表示多维数组,所以这里是维度;比如 int count[4][3] 数组,这里维度就是2;

fFeature —— 表示数组成员的类型,以及内存分配方式

cbElements —— 数组元素的大小;比如 int count[4][3] 数组,元素大小一般是4个字节(和编译器相关);比如 VARIANT var[4],那么大小就是 sizeof(VARIANT), 在VS2019上是16字节。

cLocks —— 数组被加锁的次数。比如 SafeArrayAccessData 访问数据的时候会加锁(次数+1),SafeArrayUnaccessData结束访问数据的时候会解锁(次数-1)

pvData —— 数据,指向实际的数据块。

rgsabound —— 每个维度的边界。这是一个数组,每个维度对应一个元素。比如 int count[4][3],那么就是{ {4, 0}, {3, 0}}。因为我们下标想从0开始,所以lLbound指定成了0,也可以用其他值。

typedef struct tagSAFEARRAY
    {
    USHORT cDims;
    USHORT fFeatures;
    ULONG cbElements;
    ULONG cLocks;
    PVOID pvData;
    SAFEARRAYBOUND rgsabound[ 1 ];
    } 	SAFEARRAY;

 SAFEARRAYBOUND结构

这个结构是我们创建数组时传入的,指定我们要创建的数组长度和边界。

cElements : 当前维度的长度,元素的个数

lLbound : 左边界,也就是第一个元素的索引。

typedef struct tagSAFEARRAYBOUND
    {
    ULONG cElements;
    LONG lLbound;
    } 	SAFEARRAYBOUND;

SafeArrayCreate

创建CT_ARRAY类型数据

vt —— 变量类型

cDims —— 维度

rgsabound —— 边界描述数组

SAFEARRAY * SafeArrayCreate(
  VARTYPE        vt,
  UINT           cDims,
  SAFEARRAYBOUND *rgsabound
);

SafeArrayPutElement

设置单个元素

SafeArrayGetElement

获取单个元素

SafeArrayAccessData

对SAFEARRAY进行加锁,并将数组指针返回,必须成对的调用SafeArrayUnaccessData来解锁。由于直接访问,速度比putElement/getElement快多了。

HRESULT SafeArrayAccessData(
  SAFEARRAY  *psa,
  void HUGEP **ppvData
);

SafeArrayUnaccessData

解锁数组

SafeArrayDestroy

销毁数组,以及数组里的所有元素。针对元素类型为VARIANT,调用VariantClear;元素为BSTR调用SysFreeString。

参考:https://docs.microsoft.com/en-us/windows/win32/api/_automat/

猜你喜欢

转载自blog.csdn.net/zamely/article/details/113645168