----哆啦刘小洋 原创,转载需说明出处 2023-01-04

SgxVariantArrayT:支持多维数组的变体类型

  • 1 简介
  • 2 方法原理
    • 2.1 继承于_variant_t
    • 2.2 模板类型到VARIANT VT的转换
  • 3 主要方法(接口)
  • 4 与CArray、vector数组的转换
  • 5 Automation中的应用实例

1 简介

VRIANT变体类型是Com技术中的一种标准数据类型,Vb中的变体也是这种类型,在针对Com编程过程中,比如AutoCAD、Surfer、Excel、Word中使用自动化Automation(OLE)功能时,经常遇到VARIANT数组的情况,在VC中使用VARIANT数组很繁琐,特别是多维数组。本文介绍了一种封装VARIANT数组的方法并附带了完整的免费代码,具备以下主要功能:1)最多4维数组的支持;2)使用VARIANT数组类似于CArray、vector,也类似与Vb中的动态数组;3)支持CArray、vector与VARIANT的转换(1~4维)。本文的代码基于VC2012及以上(将代码中的">>"中间留个空格,也可以用于vc6)。

2 方法原理

其实没有什么原理,就是把VC中繁琐的SafeArray申明、赋值、设置都封装到一个VAIRANT继承类中。采用模版类,是为了读取和写入数组数据书写更方便。主要关键点就两个:

2.1 继承于_variant_t

如下:

template <class T>
class CSgxVariantArrayT : public _variant_t
{//没有成员变量,保持和VARIANT最大的兼容。
};

2.2 模板类型到VARIANT VT的转换

VARIANT是一种标准数据格式,因此只能对应有限的常用数据类型。常用的VT类型和c语言类型对照关系如下:
VT_R8 -> double
VT_R4 -> float
VT_I4 / VT_INT -> int / long
VT_BSTR -> BSTR
VT_I1 -> char
VT_I2 -> short

因此在构造时根据模板参数来获取对应的vt值,代码如下:

template <class T>
class CSgxVariantArrayT : public _variant_t
{//...void CalcVT(){if (typeid(T) == typeid(double))vt = VT_R8;else if (typeid(T) == typeid(int))vt = VT_I4;else if (typeid(T) == typeid(UINT))vt = VT_UI4;else if (typeid(T) == typeid(float))vt = VT_R4;else if (typeid(T) == typeid(char))vt = VT_I1;else if (typeid(T) == typeid(UCHAR))vt = VT_UI1;else if (typeid(T) == typeid(BOOL))vt = VT_I4;else if (typeid(T) == typeid(short))vt = VT_I2;else if (typeid(T) == typeid(unsigned short))vt = VT_UI2;else if (typeid(T) == typeid(bool))vt = VT_BOOL;else if (typeid(T) == typeid(BSTR))vt = VT_BSTR;else if (typeid(T) == typeid(__int64))vt = VT_I8;else{ASSERT(FALSE);throw ("data type not supported");}vt |= VT_ARRAY;}
};

3 主要方法(接口)

template <class T>
class CSgxVariantArrayT : public _variant_t
{public://构造CSgxVariantArrayT(void);CSgxVariantArrayT(ULONG nCount, T* pData = NULL);CSgxVariantArrayT(const VARIANT& v);//获取某一维的元素个数long GetSize(long nDim);//设置数组大小BOOL Redim(long n1);BOOL Redim(long n1, long n2);BOOL Redim(long n1, long n2, long n3);BOOL Redim(long n1, long n2, long n3, long n4);//获取数组元素(读写)T& operator()(long n1);T& operator()(long n1, long n2);T& operator()(long n1, long n2, long n3);T& operator()(long n1, long n2, long n3, long n4);     //写数组元素(另一种写方案,用于数组转换)HRESULT SetAt(long nIndex, variant_t v);HRESULT SetAt(long n1, long n2, variant_t v);HRESULT SetAt(long n1, long n2, long n3, variant_t v);HRESULT SetAt(long n1, long n2, long n3, long n4, variant_t v);
};

最多支持到4维数组。实现都是利用Windows系统函数SafeArrayRedim、SafeArrayCreate、SafeArrayDestroy等,一句一句把他们封装起来。另外,采用了重载()的方式,很遗憾,多维数组无法采用重载[]的方式提供类似 arr[][][] 读取数据的方法。
想了解具体实现,请参见文末附带的源代码。
使用方法的示例代码如下:

#include "SgxVariantArrayT.h"void test()
{CSgxVariantArrayT<double> darr(5); //申明一个变体数组,初始化5个元素darr(0) = 1.0;darr(4) = 5.0;//读取索引[4]位置的数据darr.Redim(2, 3);//变成二维数组darr(0, 0) = 1.0;darr(0, 1) = 2.0;//读取索引[0][1]位置的数据double d = darr(0, 1);
}

特别的,VARIANT支持的字符串为BSTR类型,因此使用时要注意:

#include "SgxVariantArrayT.h"
#include <afxtempl.h> //for CString
#include <string> //for std::stringvoid test_str()
{CSgxVariantArrayT<BSTR> sarr(5); //必须为BSTRsarr(0) = bstr_t("xx").copy();//注意这里要用.copy()得到一个新的bstr_t实例,否则临时对象会共用一个实例,导致数组赋值后只能得到一个相同的值CString s("yy"), s1;sarr(4) = bstr_t(s).copy();//用CString 赋值s1 = sarr(0);//赋值给CStringstd::string ss("ss"), ss1;sarr(2) = bstr_t(ss.c_str()).copy();//用std::string 赋值ss1 = bstr_t(sarr(2));//赋值给std::string
}

4 与CArray、vector数组的转换

支持MFC CArray、std::vector数组以及一维指针数组。

#    define CArray1T CArray<T, T>
#   define CArray2T CArray<CArray<T, T>>
#   define vector1T std::vector<T>
#   define vector2T std::vector<std::vector<T>>
//...template <class T>
class CSgxVariantArrayT : public _variant_t
{//一维指针数组互换BOOL From(T* arr, int n1);BOOL ToArray(T* arr, int n1);//MFC CArray数组互换BOOL From(CArray1T& arr);BOOL From(CArray2T& arr);...BOOL ToArray(CArray1T& arr);BOOL ToArray(CArray2T& arr);...//std::vector数组互换BOOL From(vector1T& arr);    BOOL From(vector2T& arr);...BOOL ToArray(vector1T& arr);BOOL ToArray(vector2T& arr);};

对CString std::string数组的转化必须要做特殊处理。略过。感兴趣可查看源代码FromStringArray,ToStringArray函数。

示例代码:

#include "SgxVariantArrayT.h"
void test_SgxVariantArrayT()
{long i, j, k, m, nn;//test with CArray{//一维CSgxVariantArrayT<double> vd;CArray<double, double> ad;ad.SetSize(6);for (i = 0; i < 6; ++i)ad[i] = i;vd.From(ad);vd.ToArray(ad);//二维nn = 0;CArray2(double) ad2;CSgxVariantArrayT<double>::SetArraySize(ad2, 2, 3);for (j = 0; j < 3; ++j)for (i = 0; i < 2; ++i)ad2[i][j] = nn++;vd.From(ad2);vd.ToArray(ad2);}   //test with CStringArray{CStringArray as;CSgxVariantArrayT<BSTR> sv;as.SetSize(6);for (i = 0; i < 6; ++i)as[i].Format(_T("%d"), i * 10);sv.FromStringArray(as);sv(0) = bstr_t(as[1]).copy();//important with copy(), or sv(0) = sv(1)sv(1) = bstr_t(as[0]).copy();sv.ToStringArray(as);}//test with vector{//一维CSgxVariantArrayT<double> vd;vector1(double) ad;ad.resize(6);for (i = 0; i < 6; ++i)ad[i] = i;vd.From(ad);vd.ToArray(ad);//二维nn = 0;vector2(double) ad2;CSgxVariantArrayT<double>::SetArraySize(ad2, 2, 3);for (j = 0; j < 3; ++j)for (i = 0; i < 2; ++i)ad2[i][j] = nn++;vd.From(ad2);vd.ToArray(ad2);}//test with std::string Array{std::vector<std::string> as;char* cs[] = { "a", "b" , "c" , "d" , "e" , "f" };CSgxVariantArrayT<BSTR> sv;as.resize(6);for (i = 0; i < 6; ++i)as[i] = cs[i];sv.FromStringArray(as);sv(0) = bstr_t("xxx").copy();//important with copy(), or sv(0) = sv(1)sv(1) = bstr_t("yyy").copy();sv.ToStringArray(as);}
}

5 Automation中的应用实例

比如VC调用AutoCAD自动化:

#import "acax20chs.tlb" no_namespace named_guids
#include "SgxVariantArrayT.h"void OnTest_Interface_vc2022()
{CoInitialize(NULL);IAcadApplicationPtr     pApp;IAcadDocumentsPtr      pDocs;IAcadDocumentPtr      pDoc;IAcadModelSpacePtr     pMs;HRESULT   h = NOERROR;CLSID   clsid;//获取Class IDh = ::CLSIDFromProgID(OLESTR("AutoCad.Application"), &clsid);if (FAILED(h))return;//获取正在运行的对象h = pApp.GetActiveObject(clsid);if (!SUCCEEDED(h)){//没有正在运行的对象,就创建一个h = pApp.CreateInstance(clsid, NULL, CLSCTX_ALL);if (FAILED(h))return;}pApp->WindowState = AcWindowState::acMax;pApp->Visible = VARIANT_TRUE;//新建一个AutoCAD文档pApp->get_Documents(&pDocs);pDoc = pDocs->Add();//模型空间pDoc->get_ModelSpace(&pMs);//添加一条多义线CSgxVariantArrayT<double> arr(6);arr(0) = 0.0; arr(1) = 0.0; arr(2) = 0.0;arr(3) = 10.0; arr(4) = 10.0; arr(5) = 0.0;pMs->AddPolyline(arr);pApp->ZoomAll();
}

下载源代码。(免费、免积分)。源代码测试请调用静态函数 CSgxVariantArrayT::test()。

#include "SgxVariantArrayT.h"
void test()
{CSgxVariantArrayT<int>::test();
}

如果你觉得有帮助,别忘了帮我点个关注或点个赞!

SegeX SgxVariantArrayT:VC封装支持多维数组的变体类型(VRIANT 、SafeArray)(附免费免积分源代码)相关推荐

  1. 根据数组中的某个键值大小进行排序,仅支持二维数组

    /**     * 根据数组中的某个键值大小进行排序,仅支持二维数组     *     * @param array $array 排序数组     * @param string $key 键值 ...

  2. Matlab常见报错:错误使用 conv2不支持 N 维数组;cell类型数组不支持运算符

    一.错误使用 conv2不支持 N 维数组: 错误样例: 原因:提示错误使用 conv2不支持 N 维数组,可能是因为你读取的图像并不是灰度图像,而是RGB图像,有red/green/blue三种颜色 ...

  3. 【HDU】1251统计难题 (字典树:二维数组,结构体数组,链表,map)

    使用二维数组或者结构体数组都可以,但是在计数的时候有一点点小区别 一.结构体数组 #include <cstdio> #include <cstring> #include & ...

  4. NEFU 大一寒假培训【一】二维数组、结构体

    主题:二维数组.结构体 A 二维矩阵对角线和 Description 计算m×m的方阵的对角线所有元素的和 Input 输入数据有多组,每组第1行为m (2<=m<=10),接下来有m行m ...

  5. acm新手小白必看系列之(1)——二维数组及结构体精讲附带例题

    *acm新手小白必看系列之(1)--二维数组及结构体 ** c++准备工作** (可能小白像我一样也是学习的c语言) 万能头文件,放在第一行 #include<bits/stdc++.h> ...

  6. php variant 数组,php – 如何将8209数组对象变体转换为VT_VARIANT

    我正在调用一个COM对象方法,该方法在我的PHP代码中返回8209类型的数组变量对象. $com_VArray = $com_Object->objectMethod; //Is a 8209 ...

  7. matlab多维数组、结构体数组

    1.多维数组 第三维称为页,需要注意的是每一页存放的二维数组维度要一致,也就是行列数要一致... 1 2 3 4 5 6 7 a=[1,2;     3,4]; b=[2,2;     5,6]; A ...

  8. C语言一维数组、二维数组、结构体的初始化

    C语言数组的初始化表示方法 一.C语言一维数组初始化: (1)在定义数组时对数组元素赋以初值.如: static int a[10]={0,1,2,3,4,5,6,7,8,9}; 经过上面的定义和初始 ...

  9. C语言动态二维数组,结构体动态申请内存空间

    在C语言中,申请一般数组时,数组大小必须是常量.即使是赋了特定值的变量,也不行,比如:int n=3;int a[3];这样的做法是错误的,我们需要动态申请数组内存,如下申请一个动态整数(int)二维 ...

最新文章

  1. JavaScript递归应用与实践
  2. 【NOIP2017模拟6.25】小W的动漫
  3. Hadoop! | 大数据百科 | 数据观 | 中国大数据产业观察_大数据门户
  4. ps提示“脚本错误-50出现一般Photoshop错误的解决方法
  5. “读心术”再升级,数字识别准确率可达90%
  6. 象棋软件最强手机版_我说它是地表手机最强清理软件,没意见吧
  7. PHP获取git提交信意_代码提交规范检查与修复 php_codesniffer + composer-git-hooks
  8. 2022年电工杯B题参赛历程
  9. pyLDA系列︱考量时间因素的动态主题模型(Dynamic Topic Models)
  10. 使用JQuery.slideBox实现图片滚动效果
  11. 使用kali破解win7密码
  12. C语言编程入门——综合练习(一)
  13. 与门非门在电子计算机中的应用,与非门电路
  14. java给文件夹加密码_用JavaScrpt 实现文件夹轻松加密 (转)
  15. ips细胞治疗糖尿病研究进展综述
  16. 程序员专属段子集锦 10/10
  17. 网易云信圈组上线实时互动频道,「破冰」弱关系社交
  18. python sys.path用法
  19. 「String用法总结」
  20. 用python画微信表情_【一点资讯】“裂开了,苦涩了,翻白眼”!我用Python画出微信新出的表情包 www.yidianzixun.com...

热门文章

  1. 机械秒表的使用方法_秒表的使用方法!
  2. “苹果”在中国的血汗工厂
  3. Task 编程中的异常处理
  4. [kaggle]泰坦尼克预测(代码解析)
  5. 纯CSS3模拟iPhone X背景切换动画
  6. 匹兹堡大学约翰斯敦计算机学院,英语翻译翻译Every human being,no matter what he is doing,gives off...
  7. Engine中如何实现ArcMap中的Split Polygons
  8. 计算机休眠会断电吗,电脑「睡眠」和「休眠」原来有这么大区别,下次别用错了。...
  9. TensorFlow2.0-GPU加速
  10. 日记侠:如何用手机月入万元,只需从这5步开始