您的位置:首页 > 编程语言 > C语言/C++

从C++到COM,学习笔记(6)

2015-08-24 17:25 190 查看
转自:http://blog.sina.com.cn/s/blog_701b41e40100m4jq.html

AddRef和Release

一. IUnknown接口

按照COM标准,所有的COM接口的前三个函数都必须是IUnknown接口的那三个函数:QueryInterface(),AddRef()和Release()。如果用C++表述的话,就是所有的COM接口都必须从IUnknown这个虚基类继承而来。

QueryInterface()的作用前面已经说过了,是根据IID查询当前COM对象是否有此接口,并返回接口指针。那么AddRef()和Release()呢?

按照字面的意思,AddRef()的意思就是说增加当此接口被引用的次数,而Release()则是释放。实际上也差不多就是这么回事……虽然Release()表面上看起来起一个SubRef()的名字能够更加和AddRef()匹配一点。

二. COM对象的创建过程和引用计数的需求

如果按照一般的思想,COM对象被创建后,大家自由使用就是了,为了什么非要引入AddRef()和Release()函数?其实这里涉及到的问题主要是COM对象的生存期问题。一个COM对象何时被谁创建?何时又被谁释放呢?

最自然的回答肯定是需要时创建以实现应用,不需要时释放以节约系统资源。但是这里实现就有很多问题:首先,按照前面所述,客户并不真正的了解COM对象,它只能提供CLSID来定位COM对象,提供IID来查询接口,然后能做的就是利用接口实现功能。在Windows的COM库中,用CoCreateInstance()函数来封装客户端的调用,然后CoCreateInstance()根据CLSID在注册表中找到实现该对象保存的文件,再根据调用方式的不同(进程内/进程外)将该文件装载入内存,创建类厂,然后用类厂的CreateInstance()接口创建COM对象并返回IID指定的接口。这一连串的工作分的很细,主要的目的就是用中间层,比如COM库函数和标准IClassFactory接口等隔开用户和具体COM对象,实现更好地封装。

既然如此,具体生成COM对象的并不是客户端而是COM组件中和COM对象对应的类厂对象。因此,释放或者说从内存中卸载COM对象的任务也不能是客户端完成。而在COM组件中,类厂只管生成,那么释放的任务就只能交给COM对象自己完成了。

所以,最后的要求就变成了COM对象自己需要知道什么时候能够释放自身,那么就需要有一个量来表示现在到底又多少用户在使用此COM对象,这就是引用计数了。

三. 引用计数的实现

实现引用计数的方法很简单,用一个全局的变量来保存计数,多一个引用时加一,少一个引用时减一。COM规定当创建COM对象时先把计数从0加到1,然后加加减减,直到计数变到0,说明已经没有用户使用该COM对象,那么这个就可以释放资源了。

由于客户端只能对接口操作,因此AddRef()和Release()需要保证能够在任何接口下都能调用,包括IUnknown。这样一来,这两个函数和QueryInterface()并列成为IUnknown的三个成员也就顺理成章了。

这里还有一些小问题。比如说是针对COM对象整体计数呢,还是针对各个接口计数?COM标准没有硬性规定,但是作为COM对象的使用者,客户端必须考虑到不同情况,所以必须是调用增加或减少引用的那个接口的AddRef()和Release()。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: