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/