VARIANT 的高级应用

本文深入解析如何使用SafeArray封装结构体类型数据,包括获取结构体对应的IRecordInfo接口、构造SafeArray及操作数组元素的详细步骤。通过实例演示,帮助开发者掌握自动化环境中数组参数传递的技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何构造一个元素类型为Struct的SafeArray:

 

在有些时候,我们需要构造一个元素类型为Struct的SafeArray,在MSDN并没有文档解释到底应该如何去做到这一点,下面的代码片断解释了如何去构造这样一个SafeArray。

假设我们有如下的Struct:

struct myStruct

{

unsigned char Name[255];

short Kind;

};

为了构造一个SafeArray,元素类型为mxStruct,首先我们必须得拿到mxStruct所对应的IRecordInfo接口,这可以通过调用GetRecordInfoFromGuids函数实现:

#import "TestStruct.tlb" no_namespace

HRESULT hr;

IRecordInfo *pRecordInfo;

hr = GetRecordInfoFromGuids(

__uuidof(TestStruct),

1,

0,

LOCALE_USER_DEFAULT,

__uuidof(mxStruct),

&pRecordInfo);

GetRecordInfoFromGuids在注册表中查询对应的Record信息,这个注册表信息位于HKCR/Record下,同时,对应的TypeLib也必须被注册在HKCR/TypeLib下面,这样GetRecordInfoFromGuids才可以查到对应的信息并返回IRecordInfo*指针。当获得了这个指针的时候,便可以通过CreateSafeArrayVectorEx来构造SafeArray:

SAFEARRAY *pArray = SafeArrayCreateVectorEx(VT_RECORD, 0, 3, pRecordInfo);

该行调用SafeArrayCreateVectorEx构造一个元素为pRecordInfo指定的结构,也就是myStruct的SafeArray,LowBound为0,元素个数为3。

对这个SafeArray中的元素赋值可以通过SafeArrayAccessData和SafeArrayUnaccessData做到:

myStruct *pStructs;

SafeArrayAccessData(pArray, (void **)&pStructs);

strcpy((char *)&pStructs[0].Name[0], "N1");

pStructs[0].Kind = 0;

strcpy((char *)&pStructs[1].Name[0], "N2");

pStructs[0].Kind = 1;

strcpy((char *)&pStructs[2].Name[0], "N3");

pStructs[0].Kind = 2;

SafeArrayUnaccessData(pArray);

SafeArrayAccessData获得数组的指针,用于修改数据,并Lock该SafeArray,防止被SafeArray被释放。而SafeArrayUnaccessData则Unlock这个SafeArray。

 

 

SAFEARRAY

  SAFEARRAY的主要目的是用于automation中的数组型参数的传递。因为在网络环境中,数组是不能直接传递的,而必须将其包装成SafeArray。实质上SafeArray就是将通常的数组增加一个描述符,说明其维数、长度、边界、元 素类型等信息。SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,然后才作为参数传送出去。在VARIANT的vt成员的 值如果包含VT_ARRAY|...,那么它所封装的就是一个SafeArray,它的parray成员即是指向SafeArray的指针。 SafeArray中元素的类型可以是VARIANT能封装的任何类型,包括VARIANT类型本身。
  使用SafeArray的具体步骤:
  方法一:
  包装一个SafeArray:
  (1). 定义变量,如:
  VARIANT varChunk;
  SAFEARRAY *psa;
  SAFEARRAYBOUND rgsabound[1];
  (2). 创建SafeArray描述符:
  uIsRead=f.Read(bVal,ChunkSize);//read array from a file.
  if(uIsRead==0)break;
  rgsabound[0].cElements =uIsRead;
  rgsabound[0].lLbound = 0;
  psa = SafeArrayCreate(VT_UI1,1,rgsabound);
  (3). 放置数据元素到SafeArray:
  for(long index=0;index<uIsRead;index++)
  {
  if(FAILED(SafeArrayPutElement(psa,&index,&bVal)))
  ::MessageBox(NULL,"出毛病了。","提示",MB_OK | MB_ICONWARNING);
  }
  一个一个地放,挺麻烦的。
  (4). 封装到VARIANT内:
  varChunk.vt = VT_ARRAY|VT_UI1;
  varChunk.parray = psa;
  这样就可以将varChunk作为参数传送出去了。
  读取SafeArray中的数据的步骤:
  (1). 用SafeArrayGetElement一个一个地读
  BYTE buf[lIsRead];
  for(long index=0;index<lIsRead;index++)
  {
  ::SafeArrayGetElement(varChunk.parray,&index,buf+index);
  }
  就读到缓冲区buf里了。
  方法二:
  使用SafeArrayAccessData直接读写SafeArray的缓冲区:
  (1). 读缓冲区:
  BYTE *buf;
  SafeArrayAccessData(varChunk.parray, (void **)&buf);
  f.Write(buf,lIsRead);
  SafeArrayUnaccessData(varChunk.parray);
  (2). 写缓冲区:
  BYTE *buf;
  ::SafeArrayAccessData(psa, (void **)&buf);
  for(long index=0;index<uIsRead;index++)
  {
  buf=bVal;
  }
  ::SafeArrayUnaccessData(psa);
  varChunk.vt = VT_ARRAY|VT_UI1;
  varChunk.parray = psa;
  这种方法读写SafeArray都可以,它直接操纵SafeArray的数据缓冲区,比用SafeArrayGetElement和 SafeArrayPutElement速度快。特别适合于读取数据。但用完之后不要忘了调用::SafeArrayUnaccessData (psa),否则会出错的。
  如果SafeArray中存的是BSTR的二维数组,则代码如下:
  if(varChunk.vt = VT_ARRAY | VT_BSTR)
  {
  BSTR* buf;
  long LBound; // 数组下界
  long UBound; // 数组上界
  SafeArrayAccessData(varChunk.parray, (void **)&buf);
  SafeArrayGetLBound(varChunk.parray, 1, &LBound);
  SafeArrayGetUBound(varChunk.parray, 1, &UBound);
  for(long i = LBound; i < UBound; i ++)
  {
  CString str(buf);
  MessageBox(str);
  }
  SafeArrayUnaccessData(varChunk.parray);
  }
### Variant 数据类型概述 Variant 是编程语言中的一个重要概念,在不同的上下文中有着特定的意义。通常情况下,variant 类型表示可以容纳多种不同类型的数据结构[^1]。 #### 特征与用途 - **多态性支持**:Variant 能够存储并处理不同种类的基础数据类型(如整数、浮点数、字符串等),这使得它非常适合用于那些需要动态改变其内部所含具体类型的场景。 - **内存效率高**:相较于创建多个独立变量来分别保存各种可能的情况而言,使用 variant 可以更有效地利用计算机资源,因为只需要维护单一对象即可实现相同功能。 #### 编程实践举例 下面是一个简单的 C++ 实现例子,展示了如何定义和操作 `std::variant`: ```cpp #include <iostream> #include <string> #include <variant> int main() { std::variant<int, double, std::string> myVar; // Assign an integer value. myVar = 42; if (myVar.index() == 0) { // Check type index for int std::cout << "Integer Value: " << std::get<int>(myVar) << '\n'; } // Change content to string. myVar = "Hello World"; try { // Attempting direct access without checking might throw bad_variant_access exception. auto strValue = std::get<std::string>(myVar); std::cout << "String Content: " << strValue << "\n"; } catch(const std::bad_variant_access& e){ std::cerr<<e.what()<<'\n'; } } ``` 此代码片段说明了怎样通过标准库提供的工具安全地访问 variant 中的内容,并处理潜在异常情况下的错误管理机制。 #### 应用领域扩展思考 除了上述基本特性外,variant 还广泛应用于函数式编程范式中作为代数数据类型的一部分;以及在某些高级编译器优化技术里扮演着重要角色,比如模式匹配算法的设计等方面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值