ATL提供了很多复杂数据类型的包装类,使用这些包装类可以大大减小开发工作量,但是他们使用起来也有许多坑,需要注意,本文就ATL常用包装类的用法和坑详细说明,力图说明产生这些坑的原因和使用注意事项。本文基于VS2008 ATL,这一版修复了一些之前的bug。

先说通用的注意事项,所有的帮助类都类似智能指针特性(没有引用),如下:

1.析构时释放资源

2.赋值时,先释放原来的内容,再分配创建新的内容

这要求使用时必须注意:

1.在CoInitialize和CoUninitialize内使用接口指针

2.变量的生存周期,特别是栈上的变量

1.CComBSTR

BSTR使用需要注意两点:

1.NULL是合法字符串,BSTR可能只包含NULL也可能中间包含NULL

2.BSTR分配和释放使用对应的Sys...函数,否则很容易出现内存泄漏

常用构造如下:

 CComBSTR bstr1(OLESTR("Test1"));CComBSTR bstr2(64, (LPCOLESTR)NULL);  //支持NULL空字符CComBSTR bstr3(GUID_TEST);               //支持GUID

支持长度为64内容为NULL的字符串,支持GUID直接转成字符串。

如下赋值,bstr4内容最终为Test4,因为默认=赋值是按照LPWSTR字符串算的,\0就标记了字符串结束。如果需要赋值包含\0的BSTR字符串需要使用AppendBSTR,这个内部封装了SysAllocStringByteLen.

CComBSTR bstr4;
bstr4 = OLESTR("Test 4\0Test 4");BSTR bt = ::SysAllocStringLen(OLESTR("Test 5\0Test 6"), 13);
CComBSTR bstr5;
bstr5.AssignBSTR(bt);                   //包含空字符时的赋值

使用&取CcomBSTR地址时,返回的是BSTR字符串,如果此时直接解引用操作返回的是BSTR内容,=会导致直接覆盖原有的BSTR,导致内存泄露。

void GetBSTR1(BSTR* pBstr)
{CComBSTR bstr(OLESTR("Test GetBSTR1"));*pBstr = bstr.Detach();
}void GetBSTR2(BSTR* pBstr)
{::SysReAllocString(pBstr, OLESTR("Test GetBSTR2"));
}CComBSTR bstr6 = OLESTR("Test 7");
GetBSTR1(&bstr6);
GetBSTR2(&bstr6);

可以看到,GetBSTR1中直接对BSTR赋值了,导致了内存泄漏,此时 可开启ATL的ATL_CCOMBSTR_ADDRESS_OF_ASSERT宏,该宏判断如果取&时,CComBSTR不为空则报ASSERT警告。也可以参考GetBSTR2中,可以使用函数SysReallocString来处理这种情况。

2.CComVariant

Variant使用时需要VariantInit,然后指定类型和数据,使用完需要VariantClear清除资源。CcomVariant为我们能封装了整个过程,使用时直接赋值就行,模板实例化过程中会自动的找到对应类型,使用完自动释放,如下:

 CComVariant v1 = 10;CComVariant v2 = 10.2;CComVariant v3 = OLESTR("test");     //默认转成BSTR

唯一需要注意的是, CComVariant不能使用未初始化的VARIANT初始化(使用_ATL_NO_VARIANT_THROW宏检测),没有初始化的CComVariant也不能Detach。

3.CComSafeArray

需要引入头文件atlsafe.h。

CComSafeArray主要是为了简化SAFEARRAY的操作,常用操作如下:

void TestSafeArray()
{//构造CComSafeArray<long>      sa1(10);        //10个long元素,下标0开始CComSafeArray<double> sa2(5,1);       //5个double元素,下标1开始CComSafeArrayBound bound3(5,1);CComSafeArray<double> sa3(bound3);    //5个double元素,下标1开始CComSafeArrayBound bound40(3);CComSafeArrayBound bound41(4);CComSafeArrayBound bound4[] = {bound40, bound41};CComSafeArray<double>  sa4(bound4, 2); //2行3列double元素/*****1维*****///添加CComSafeArray<int> sa5;sa5.Add(7);int arr[] = {8, 9};sa5.Add(2, arr);sa5.Add(sa5);//访问for (int i=0; i<sa5.GetCount(); i++){wcout << sa5.GetAt(i) << endl;}//设置sa5.SetAt(0,77);for (int i=0; i<sa5.GetCount(); i++){wcout << sa5.GetAt(i) << endl;}/*****多维*****/LONG index01[] = {1, 0};LONG index11[] = {1, 1};LONG index23[] = {3, 2};sa4.MultiDimSetAt(index01, 10.0);sa4.MultiDimSetAt(index11, 6.8);sa4.MultiDimSetAt(index23, 3.2);wcout << sa4.GetCount(0) << sa4.GetCount(1) << endl;for (int i=0; i<sa4.GetCount(0); i++){for (int j=0; j<sa4.GetCount(1); j++){LONG index[2] = {0};index[0] = j;index[1] = i;double dbVal = 0;if (SUCCEEDED(sa4.MultiDimGetAt(index, dbVal)));{wcout << "(" << i << "," << j << ")="  << dbVal << endl;}}}
}

需要注意的是:

1.CComSafeArray使用模板和宏技术结合,将输入类型int等等映射为实际COM V_I4/V_I8。对于VARIANT/BSTR/IDispatch和IUnknown采用特化技术,这些类型Get出来后会自动转成CComVariant/CComBSTR/CComPtr,Add/SetAt时通过指明bCopy参数来决定是使用拷贝还是托管现有。

2.CComSafeArray 创建后会调用Lock,对应GlobalLock函数,直到销毁调用UnLock,对应GlobalUnlock,这样做是假设用户一直需要操作SafeArray数据。

3.Attach和拷贝构造会校验元素类型,最好不要直接通过GetSafeArrayPtr操作指针。

4.CComPtr和CComQIPtr

原生COM创建接口时需要使用CoCreateInstance,传入一大堆参数,调用麻烦。

CComPtr和CComQIPtr大大简化了这一流程。通过内建扩展结合_uuidof,利用模板类是实现了加速编写。后者相对前者,可以在赋值时动态查找接口。

另外使用IDispatch接口时,Invoke时传参非常麻烦,这些这两个类中都做了封装。

演示如下:

void TestComPtr()
{CoInitialize(NULL);{CComPtr<IDog> spDog;HRESULT hr = spDog.CoCreateInstance(CLSID_CAnimal);if (SUCCEEDED(hr)){spDog->Wangwang();}CComQIPtr<ICat> spCat = spDog;if (spCat){spCat->Miaomiao();CComVariant    strWord(L"抱抱");CComVariant nAge(10);CComPtr<IDispatch> spCatDisp(spCat);spCatDisp.Invoke2(2, &strWord, &nAge);}}CoUninitialize();
}

可以看到这里spCat赋值时,动态查找了ICat接口。

IDispatch接口可直接调用Invoke1/Invoke2等参数。

需要注意的是:

1.赋值时,会自动AddRef

2.如演示程序,变量周期必须在COM库作用范围内

3.使用->和.调用区别在于,前者调用内嵌指针,后者调用库封装的逻辑。一些函数比如Release需要使用.访问以调用对应的管理逻辑。

详细内容可参考《ATL深入解析》

完整演示代码下载链接

原创,转载请注明来自http://blog.csdn.net/wenzhou1219

14.说说ATL常用包装类的用法和坑相关推荐

  1. TIA博途SCL入门学习(二)常用基本控制语句用法和举例

    TIA博途SCL入门学习(二)常用基本控制语句用法和举例 FOR循环语句 FOR循环可以指定循环的次数,在使用这种循环的时候需要先定义一个INT型变量,并指定计数范围,即循环次数,直到循环次数到达设定 ...

  2. 14个vscode常用插件 php

    14个vscode常用插件 1.auto rename tag, html自动更新配对标签名称: 2.highlight matching tag,自动高亮显示结束括号/标签: 3.bracket p ...

  3. Ionic使用常用插件时遇到的坑与解决方法

    一. 什么是Ionic Ionic 是一个强大的 HTML5 应用程序开发框架(HTML5 Hybrid Mobile App Framework ). 可以帮助您使用 Web 技术,比如 HTML. ...

  4. 14个最常用的app测试工具推荐,拿走不谢!

    UI自动化测试工具 通知:[公众号更名为:程序员臻叔] 关注领福利: 回复「测试」:获取最常用的测试用例模版+常用的测试工具. 回复「面试」:臻叔原创<测试岗笔面试真题宝典> 回复「简历」 ...

  5. 程序员常用的经典算法和OJ网站

    一. Online Judge简介: Online Judge系统(简称OJ)是一个在线的判题系统.用户可以在线提交程序多种程序(如C.C++.Pascal)源代码,系统对源代码进行编译和执行,并通过 ...

  6. 数据结构和算法-14.程序员常用10种算法

    1. 二分查找算法(非递归) 1.1 介绍 二分查找算法只适用于从有序的数列种进行查找,将数列排序后再进行查找 二分查找法的运行时间为对数时间O(log2 n),即查找到需要的目标位置最多只需要log ...

  7. arcgis python实例_ArcGIS Python编程案例(14)-五个常用Python处理任务

    我们将在本章介绍以下案例: 从分隔符文本文件中读取数据 发送电子邮件 访问FTP服务器中的文件 创建ZIP文件 读取XML文件 引言 在本章中,你将学习如何编写Python脚本来执行常用的处理任务.这 ...

  8. Windows学习总结(14)——最常用的Windows快捷键再总结

    windows常用快捷键再总结如下:

  9. 14款前端常用的富文本编辑器插件

    富文本编辑器是一种可内嵌于浏览器,所见即所得的文本编辑器.它提供类似于Office Word 的编辑功能,方便那些不太懂html用户使用,富文本编辑器的应用非常广泛,它的历史与图文网页诞生的历史几乎一 ...

最新文章

  1. 美国对六种新兴技术实施控制:EUV和5nm相关技术在列
  2. pwnable.kr lotto题解
  3. VB 6.0中的数据连接模块
  4. oauth2.0授权码_OAUTH 2.0授权码授予
  5. 怎么用计算机打分数,电脑excel中分数怎么打出来(图解excel分数输入法)
  6. Yum包管理工具的20个常用命令
  7. html图片实现左右滑动,jquery实现左右滑动式轮播图
  8. .net面向对象学习笔记
  9. linux的ftp指令发邮件,三种使用Linux命令发送邮件
  10. 《基于MFC的OpenGL编程》 13 part 创建2D 和 3D 文字
  11. (5)Matplotlib_grid
  12. 弦图(Chordal Graph)学习小记
  13. MySQL5.7版本64位下载及安装详细教程
  14. 数据时代的来临,大数据价值主要体现在哪几个方面?
  15. websphere html 缓存,如何清除WebSphere类缓存
  16. vue+cordova 实现第三方登录( QQ 微信 微博)之微博登录
  17. 测试基础知识1 》》软件测试入门
  18. 法国计算机工程师学院排名,法国90所工程师学院最新排行榜
  19. 20170627总结
  20. 2021年12月青少年C/C++软件编程(四级)等级考试试卷及答案解析

热门文章

  1. V3S-Zero 网络篇章 Linux5.2
  2. 和大于等于target的最短子数组 | 循序递进---@二十一画
  3. oracle表扬信,2019年商务英语高级写作范文:感谢与道歉函
  4. 如何让百度、Google、Yahoo等搜索引擎巨头收录你的网站
  5. 使用easyrsa来制作证书
  6. 悼念512汶川大地震遇难同胞——重建希望小学
  7. 为什么极品飞车服务器维修,极品飞车:无极限赛车无法连接服务器是什么原因...
  8. POJ 1000A+B我的入门
  9. 微店新品!微店首款《疯狂野蛮人》横版动作游戏来啦!
  10. CFSSL: 证书管理工具:3:使用CA私钥与证书签发证书