刀与剑-COM返回数组

23 篇文章 0 订阅

        COM明明是一种编程思想,是一门绝世武功。可时代忽然迈入火器,无数人抛弃掉这晦涩难懂的绝世武功,转身投入速成的技艺时代。

        “很多不懂 com 的C++程序员会自行发明一个 com 的子集,而且是蹩脚的多的子集。可惜的是,刀与剑的时代结束了,火器时代,掌握 com 这类武功已经没用了。”

---知乎网友

关于使用COM接口返回数组

        COM处理了未知语言在COM客户之间传递数组,没错。但是这个并不是什么GO之流,而是C#、VB、Delphi、asp之流甚至于py等。它模糊了语言的边界,那模糊边界自然有一个重要的前提,那就是简单易用,否则都是扯犊子。

        而Com所支持的类型其中一种十分重要的即是VARIANT ,而其中有一个很重要的类型即是SAFEARRAY 这便是安全数组类型,该类型其实就是对数组进行了一些描述如起始,边界等,但是该类型又可以修饰VARIANT 为元素的数组,简直是互相套娃无穷尽也。

        去百度一搜,好家伙。一来就是SAFEARRAYSAFEARRAYBOUND 。好家伙,这TM,你管这叫简单易用?我真滴服了,而且里面的内容弯弯绕绕,晦涩难懂,这些人写的都是什么博客,互相抄互相爬,感觉像在垃圾堆里找吃的。

COM传递数组涉及结构

SAFEARRAYBOUND:

        指示数组维数,简单来说,一维、2维甚至多维数组。因此在传递多维数组时需要一个结构描述其维度。

        结构:

typedef struct tagSAFEARRAYBOUND
    {
    ULONG cElements;//表示本维元素的数目
    LONG lLbound;//数组开始的逻辑序号,实际访问需减去这个序号
    } 	SAFEARRAYBOUND;
typedef struct tagSAFEARRAYBOUND *LPSAFEARRAYBOUND;

SAFEARRAY:

        用来实际指示数组(因为这玩意不是简简单单的指针,用指示一词),涉及的数组的操作函数的参数主体就是它

        结构:

typedef struct tagSAFEARRAY
    {
    USHORT cDims;//数组的大小
    USHORT fFeatures;//数组元素类型标记值
    ULONG cbElements;//数组元素的大小
    ULONG cLocks;//被锁定次数
    PVOID pvData;//数据指针
    SAFEARRAYBOUND rgsabound[ 1 ];//数组维数描述,如果多维数组,则本数组依次为低维到高维
    } 	SAFEARRAY;
typedef /* [wire_marshal] */ SAFEARRAY *LPSAFEARRAY;

        主要函数:

//为安全数组描述符分配内存。
HRESULT SafeArrayAllocDescriptor(
  [in]  UINT      cDims,
  [out] SAFEARRAY **ppsaOut
);


//根据SafeArrayAllocDescriptor创建的描述符为安全数组分配内存。
HRESULT SafeArrayAllocData(
  [in] SAFEARRAY *psa
);

//增加数组的锁计数,并检索指向数组数据的指针。
HRESULT SafeArrayAccessData( 
  SAFEARRAY FAR* psa, 
  void HUGEP* FAR* ppvData 
);


//递减数组的锁定计数,并使SafeArrayAccessData检索到的指针无效。
HRESULT SafeArrayUnaccessData(
  [in] SAFEARRAY *psa
);

//获取指定安全数组的任何维度的下边界
HRESULT SafeArrayGetLBound(
  [in]  SAFEARRAY *psa,
  [in]  UINT      nDim,
  [out] LONG      *plLbound
);

//获取指定安全数组的任何维度的上限。
HRESULT SafeArrayGetUBound(
  [in]  SAFEARRAY *psa,
  [in]  UINT      nDim,
  [out] LONG      *plUbound
);

//创建一个新的数组描述符,为数组分配和初始化数据,并返回一个指向新数组描述符的指针。
SAFEARRAY * SafeArrayCreate(
  [in] VARTYPE        vt,
  [in] UINT           cDims,
  [in] SAFEARRAYBOUND *rgsabound
);

//将数据元素存储在数组中的指定位置。
HRESULT SafeArrayPutElement(
  [in] SAFEARRAY *psa,
  [in] LONG      *rgIndices,
  [in] void      *pv
);

//检索数组的单个元素。
HRESULT SafeArrayGetElement(
  [in]  SAFEARRAY *psa,
  [in]  LONG      *rgIndices,
  [out] void      *pv
);

     用法可参考:https://blog.csdn.net/weikangc/article/details/45745551

          注意事项:

                1、在堆上创建数组

                2、一方创建、另一方回收

                3、接收方不能修改数组,只能读取和销毁

上面说的,全是垃圾

        按上面这么用,初始化一个数组填值都得写几十行。我只能称之为“垃圾”

        而百度去搜索的,大多数都是教你这么用,我简直了

        解决办法

        CComSafeArray 类和 CComSafeArrayBound 类。

                天不生这C++,万古图灵如长夜。

        这两个类是SAFEARRAY和SAFEARRAYBOUND 结构的装饰模板类,用c++的类可以十分方便的去完成数组的创建,描述,设值,传出。

        上代码:

        一维数组创建:

CComSafeArray<long>  csa(10);  //创建一个10个元素的以0为起始下标的一维数组  
  
CComSafeArray<long>  csa(10,0);//创建一个10个元素的以0为起始下标的一维数组  
  
CComSafeArray<long>  csa(10,1);//创建一个10个元素的以1为起始下标的一维数组

        多维数组创建:

//构建一个[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);

        数组设值和取值:

//GetAt  和  SetAt  
  
CComSafeArray<long>  sa(10);  
  
sa.SetAt(1,100);//将第2个元素设置为100  
  
long  value=sa.GetAt(2);     //获得第3个元素的值,放入到value中。 

       获得外部数组值:

void  SetArray(SAFEARRAY * psa)  
{
 CComSafeArray<long>  sa;  
  
 sa.Attach(psa);  
  
 //操作   
 .....  
  
 sa.Detach();  
 }

        传出数组:

void    GetArray(SAFEARRAY ** ppsa)  
{  
      CComSafeArray  <long> sa(10);  
  
       //...
       //设值数组的值
  
       *ppsa=sa.Detach();  
}          

        多维数组使用实例

//创建一个 【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);  

        operator []操作符:(一维可用)

//模板自然是美滋滋重载了[]
CComSafeArray  <int>  sa(5);  
  
sa[2]=100;  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值