1. 总述

对于操作原始的接口指针是比较麻烦的,需要我们自己控制引用记数、API 调用、异常处理。于是 ATL 提供了2个智能指针的模板包装类,CComPtr<> 和 CComQIPtr<>,这两个类都在 <atlbase.h> 中声明。

CComPtr和CComQIPtr是智能接口指针类,它们在销毁的时候,不需要手动去释放接口指针,在赋值的时候,也不需要手动的AddRef,在出现异常的时候,会自动处理异常,而不需要额外的异常处理代码。

CComQIPtr继承了CComPtr,使用CComPtr的地方都可以使用CComQIPtr,而且使用CComQIPtr的地方多数也可以使用CComPtr。
唯一要注意的是:CComQIPtr<> 由于使用了运算符的重载功能,它会自动帮我们调用QueryInterface()函数,因此 CComQIPtr<> 唯一的缺点就是不能定义 IUnknown * 指针。

智能指针定义方法

//智能指针smart pointer,按照匈牙利命名法,以sp开头来表示变量类型CComPtr < IUnknown > spUnk; // 正确
// 假设 IFun 是一个接口类型
CComPtr < IFun > spFun; // 正确
CComQIPtr < IFun > spFun; // 正确
CComQIPtr < IFun, &IID_IFun > spFun; // 正确
CComQIPtr < IUnknown > spUnk;//错误,CComQIPtr不能定义IUnknown指针

给智能指针赋值的方法:

CComQIPtr < IFun > spFun; // 调用构造函数,还没有赋值,被包装的内部接口指针为 NULL
CComQIPtr < IFun > spFun( pOtherInterface ); // 调用构造函数,内部接口指针赋值为
// 通过 pOtherInterface 这个普通接口指针调用QueryInterface()得到的IFun接口指针
CComQIPtr < IFun > spFun( spOtherInterface ); // 调用构造函数,内部接口指针赋值为
// 通过 spOtherInterface 这个智能接口指针调用QueryInterface()得到的IFun接口指针
CComQIPtr < IFun > spFun ( pUnknown ); // 调用构造函数,由IUnknown的QueryInterface()得到IFun接口指针
CComQIPtr < IFun > spFun = pOtherInterface; // = 运算符重载,含义和上面一样
spFun = spOtherInterface; // 同上
spFun = pUnknown; // 同上
pUnknown->QueryInterface( IID_IFun, &sp ); // 也可以通过QueryInterface赋值

智能指针赋值后,可以用条件语句判断是否合法有效

if ( spFun ){}  // 如果指针有效
if ( NULL != spFun ){} // 如果指针有效if ( !spFun ){}  // 如果指针无效
if ( NULL == spFun ){} // 如果指针无效

智能指针调用函数的方法:

spFun.CoCreateInstance(...); // 等价与 API 函数::CoCreateInstance(...)
spFun.QueryInterface(...); // 等价与 API 函数::QueryInterface() 
spFun->Add(...); // 调用内部接口指针的接口函数
spFun->QueryInterface(...); //调用内部接口指针的QueryInterface()函数,其实效果和 spFun.QueryInterface(...) 一样
spFun.Release(); // 释放内部的接口指针,同时内部指针赋值为 NULL
spFun->Release(); // 错!!!一定不要这么使用
// 因为这个调用并不把内部指针清空,那么析构的时候会被再次释放(释放了两次)

1. CComPtr

1.1 为什么需要CComPtr

COM接口指针很危险,因为使用过程中需要每一个使用者都要严格并且正确的AddRef和Release,一旦出现问题,就会造成对象不能被正常释放,或者对象被重复删除,造成程序崩溃。所以使用COM接口,必须小心翼翼才行。
但是,即使所有的代码中,都正确的AddRef和Release,也不一定能保证万无一失,例如:

void SomeApp( IHello * pHello )
{IHello* pCopy = pHello;pCopy->AddRef(); OtherApp();pCopy->Hello();pCopy->Release();
}

假设OtherApp中抛出了异常,那么pCopy->Release不就被跳过去了吗?
幸好,有CComPtr

1.2 什么是CComPtr

CComPtr被称为智能指针,是ATL提供的一个模版类,能够从语法上自动完成AddRef和Release。(源代码在atlbase.h中)
CComPtr的用法很简单,以IHello* 为例,将程序中所有接口指针类型(除了参数),都使用CComPtr < IHello > 代替即可。即程序中除了参数之外,再也不要使用IHello*,全部以CComPtr< IHello >代替。
CComPtr的用法和普通COM指针几乎一样,另外使用中有以下几点需要注意。

  1. CComPtr已经保证了AddRef和Release的正确调用,所以不需要,也不能够再调用AddRef和Release。
  2. 如果要释放一个智能指针,直接给它赋NULL值即可。
  3. CComPtr本身析构的时候会释放COM指针。
  4. 当对CComPtr使用&运算符(取指针地址)的时候,要确保CComPtr为NULL。(因为通过CComPtr的地址对CComPtr赋值时,不会自动调用AddRef,若不为NULL,则前面的指针不能释放,CComPtr会使用assert报警)
void SomeApp( IHello * pHello )
{CComPtr<IHello> pCopy = pHello;OtherApp();pCopy->Hello();
}

由于pCopy是一个局部的对象,所以即使OtherApp()抛出异常,pCopy也会被析构,指针能够被释放。

1.3 使用方法

构造函数
第一个参数为智能接口指针的类型,第二个参数为智能指针的接口ID。

CComPtr<IUnknown> punk;
//下面三个例子完全相同
CComPtr<IXXX> pno;
CComPtr<IXXX,&__uuidof(IXXX)> pno;
CComPtr<IXXX,&IID_IXXX> pno;

1.4 总结

如果不想在程序临近发布前,还因为COM指针的引用计数造成崩溃的话,就牢记这一点吧:程序中除了参数之外,不要直接使用COM指针类型,一定要全部以CComPtr代替。

2. CComQIPtr

2.1 不同之处

CComQIPtr和CComPtr的不同的地方:CComPtr只能创建固定的特定的接口指针实例。而CComQIPtr不但实现了CComPtr的所有的功能(除了CComQIPtr< IUnknown >是不合法的,除此之外其他CComPtr都可以用CComQIPtr代替。),而且当我们把一个不同类型的接口指针赋值给CComQIPtr的时候,CComQIPtr会自动的调用接口指针的QueryInterface接口,来获得对应的正确的接口指针。

2.2 使用方法

CComQIPtr可以用任何一个类型的接口指针初始化,如果初始化的值与CComQIPtr的类型相同,那么构造函数简单调用指针的AddRef;但是,如果类型不同的话,它会先调用指针的QueryInterface来获得相同的类型的接口指针,当QueryInterface失败的话,内部指针会被设置为NULL。

所有下面的代码,可以用来检测是否转换成功:

void  Func(IUnknown * punk)
{  CComQIPtr<IXXX> pno(punk);  if(pno)    {    //正确转换    pno->doSomething();    }
}

CComPtr和 CComQIPtr用法相关推荐

  1. 【CComPtr】CComPtr和CComQIPtr的区别

    2011年06月16日 下午 06:14 ATL 提供了2个智能指针的模板包装类,CComPtr<> 和 CComQIPtr<>,这两个类都在 <atlbase.h> ...

  2. 一些vc开发浏览器及插件的资料

    如何往IE工具条添加按钮 问题提出: 金山词霸.网络蚂蚁等软件安装后会向IE的工具条添加自己的按钮.按下按钮后还会作出相应的动作,这种功能是如何实现的呢?读完本文,您也可以将自己应用程序的按钮添加到I ...

  3. ATL之深入浅出书评(潘爱民)

    ATL之深入浅出 介绍一本关于ATL的书<ATL Internals> 潘爱民,5月7日,2000年 北京大学计算机研究所,100871 引言 面对计算机图书市场的繁荣景象,我经常感叹今天 ...

  4. C++个人笔记,用于Ctrl+F查询

    C++初级笔记 1.快速入门 int main() {return 0; //返回0,告诉Windows程序运行正常 } C++的标准库中的标准的输入输出对象,即键盘和显示器. 引用#include ...

  5. Jiangsheng的CSDN Digest (Oct 2005)

    CSDN 讨论总结系列: Jiangsheng的CSDN Digest (Dec 2005)(http://blog.csdn.net/jiangsheng/archive/2005/12/24/56 ...

  6. COM 组件设计与应用(七)

    COM 组件设计与应用(七) 编译.注册.调用 作者:杨老师 一.前言 上两回中,咱们用 ATL 写了第一个 COM 组件程序,这回中,主要介绍编译.注册和调用方法.示例程序你已经下载了吗?如果还没有 ...

  7. COM 学习(五)——编译、注册、调用

    "最小依赖",表示编译器会把 ATL 中必须使用的一些函数静态连接到目标程序中.这样目标文件尺寸会稍大,但独立性更强,安装方便:反之系统执行的时候需要有 ATL.DLL 文件的支持 ...

  8. ATL 实现定制的 IE 浏览器栏、工具栏和桌面工具栏

    下载源代码 关键字:Band,Desk Band,Explorer Band,Tool Band,浏览器栏,工具栏,桌面工具栏 一.引言 最近,由于工作的要求,我需要在 IE 上做一些开发工作.于是在 ...

  9. 14.说说ATL常用包装类的用法和坑

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

  10. 用CComPtr吧,COM接口指针很危险

    COM接口指针很危险,因为使用过程中需要每一个使用者都要严格并且正确的AddRef和Release,一旦出现问题,就会造成对象不能被正常释放,或者对象被重复删除,造成程序崩溃.所以使用COM接口,必须 ...

最新文章

  1. 微软职位内部推荐-Sr SDE for Win Apps Ecosystem
  2. CSDN 中秋节日礼品盒 | 中秋节快乐
  3. 初学者学python好还是c-学Python还是学C?
  4. php echo表单提交_PHP常见面试题及答案
  5. java 招聘需求_Java人员要具备哪些技能 招聘需求包括什么
  6. 线程池的简单创建和实现
  7. python 批量修改密码
  8. [GCC for C]编译选项---IDE掩盖下的天空
  9. kibana 查看索引库中文档个数_百度索引量是什么意思?和百度收录量的区别。...
  10. HALCON学习之旅(三)
  11. 啦啦啦-我又来了!!!
  12. 【C#】【MySQL】C# 查询数据库语句@Row:=@Row+1以及执行存储过程失败解决方案
  13. Android 创建与解析XML(三)—— Sax方式
  14. delphi mysql类_Delphi MySQL数据库操作类
  15. HP Loadrunner 11下载地址
  16. 实现统计二叉树叶子节点个数的算法
  17. QT版用QLCDnumber显示时间
  18. 图片生成二维码最好的工具
  19. C#通过类的继承来实现判断任意一个三角形并求出它们的周长及面积(等腰三角形,等边三角形,直角三角形,等腰直角三角形)
  20. 团队管理_第一期干部训练营心得

热门文章

  1. TableView数据源方法的执行顺序
  2. java 使用 poi 操纵 excel2003 经验总结
  3. ActivityManager: Warning: Activity not started,...
  4. C#之向ListView视图插入数据...
  5. [C++/CLI编程宝典][7]基本概念
  6. 小程序 switch 自定义_微信小程序自定义组件问题一:获取组件DOM元素
  7. Javascript异步操作(Promise)
  8. 04.electron-(使用remove模块及安全策略)
  9. swoft使用phpunit之CodeCoverage
  10. wchar_t转为char*