在写今天的文字前,我快速浏览了一下上回的《COM学习漫谈[1]》,这样可以让今天的“漫谈”,可以跟上回很好的接上,先把这叫做“圆谎”吧。还有一大喜事,我的《COM学习漫谈[1]》登上了CUBLOG的一周热点文章,好久没有上榜了,上次还是《TO_DATA使用详解》,事今已有一年之久吧。
书接上回,今天我们来看看IUnknow接口,以及每个接口都必有[或曰:支持]的三个方法AddRef,Release,QueryInterface。我们找到了接口,也就能找到了对象,也就能调用接口支持的方法。一个COM组件对象可以提供很多接口,从另一个角度来说也就是很多接口使用同一个COM组件对象。如果每使用一个接口就创建一个COM组件对象,那该多浪费啊。
我们希望是:
而不是:
这样在使用同一个COM对象提供的服务的时候,可以只创建一个COM对象,而不是调用一次就创建一次。节省了系统资源。
实现同一个COM对象在系统中只存在一份,首先要解决的问题就是:什么时候创建对象?什么时候销毁对象?正确答案:在需要的时候创建对象,在不需要的时候销毁对象。呵呵,只不过这答案讲跟不讲没有什么区别。COM技术中运用了“引用计数(reference count)”这一概念,如果对C++中的智能指针auto_ptr熟悉的话。COM里的“引用计数”和智能指针auto_ptr里的“引用计数”一样,都是用来标识当里的对象被使用的次数。当对象被引用一次就在其“引用计数器”上增加“1”,当“引用计数器”的值为“0”(这时意味着当该对象已没有被引用)时销毁对象。
现在通过两个函数AddRef(),Release()正式揭开COM对象中的“引用计数”:
AddRef()
在调用COM对象接口时,调用AddRef(),AddRef()在其接口使用的COM对象的“引用计数器”加“1”;
Release()
在引用完COM对象接口之后,调用Release(),Release()的实现如下(伪代码):
引用计数" - 1;
if("引用计数" == 0)
{
释放COM对象;
}
我们解决了什么时候创建COM对象?什么时候销毁COM对象?之后让我再看接口使用中的另外一个问题,在同一个对象中怎么从一个接口跳至另外一个接口。我们在创建一个COM对象时会返回一个且仅返回一个接口的指针。我们想要调用另外的接口该怎么办呢?
这次的答案很明确,使用的每个接口都会有的一个方法QueryInterface()
,根据传入的接口IDD(还记得吗?若不,请看上回),可以返回该IDD对应的指针,相应的也可以调用其方法了。
QueryInterface()
根据传入的接口IDD,返回接口相应的指针;
我们每一个接口都要有完成这个上面这三个功能的能力,即AddRef()
, Release()
, QueryInterface()
,从面向对象的角度来讲,一个统一的抽象表示非“基类”莫可了。COM也采用的这种方案。即定义一个“基接口”,“基接口”分别实现AddRef(),Release(),QueryInterface()方法。这个接口被命名为“IUnknow”。COM规定所有的COM接口都必须从IUnkwon继承,继承IUnkwon的三个方法的申明,进而在接口所对应的COM对象中实现这三个方法。
把上面的内容整理一下,IUnkwon申明以下三个方法:
- AddRef();
- Release();
- QueryInterface();
每个接口都必须继承IUnkwon,并实现上面的三个方法。
注:接口的继承,只继承接口的申明,并不是接口的实现。例如(伪代码):
public interface()
{
void AddRef();
void Release();
void *QueryInterface();
}
该接口本身也没有实现部分,具休的实现部分要在实现接口的类中完成,例如(伪代码):
class IA:public interface
{
private:
int m_value;
public:
IA();
~IA();
void AddRef(){m_value++;};
void Release(){m_value--; m_value == 0?Release(COM组件D):;}
}
Comments: