com技术内幕读书笔记1

COM技术内幕

第一章 组件组件:将单个应用程序分解为多个独立的部分。 组件的优点: 1. 应用程序定制 2. 组件库 3. 分布式组件 实现组件的先决条件 1. 动态链接。 2. 信息封装。 a) 封装编程语言 b) 组件必须以二进制发布 c) 组件可以自由升级 d) 组件在网络上的位置对客户程序透明 COM: COM是一个说明如何建立可动态互变组件的规范。它提供了为保证能够互操作,客户和组件必须遵循的一些标准。 COM组件: 以Win32动态链接库或可执行文件发布的可执行代码。它们的编写遵循COM规范。COM组件也是信息封装的,满足上面说过的四个封装条件。这在COM规范中说明。 COM库: 为了简化COM组件的编写,微软提供了COM库。它提供了对所有客户及组件都非常有用的组件管理服务。这不是必须的,完全可以自己从头构建COM组件。正如MFC只是为了编程方便提供了对WIN API的封装,完全可以不使用。 第二章 接口 COM接口: 对COM而言,接口是一个包含一个函数指针数组的内存结构。每个数组元素包含一个由组件所显现的函数的地址。 用户只需要知道接口,并不需要知道COM组件的细节。COM组件只是对接口的实现,而且多个COM组件可以实现同一个接口,这样可以通过替换组件实现升级和转化功能。只要接口不变,客户程序就不需要改变。 一个COM组件可以实现多个接口,具有多个功能。 COM接口的实现: COM接口可以通过多种语言实现,接口有一个二进制的标准。也就是说,表示一个接口的内存块必须具有一定的结构。客户程序用一个指向接口数据结构的指针来调用接口成员函数。接口指针实际上又指向一个指针,这第二个指针指向一组函数,称为接口寒暑表。接口函数表中每项为4个字节长的函数指针。 在C++中,可以使用抽象基类实现COM接口。抽象基类的内存结构跟接口的内存结构正好完全相同。抽象基类的指针指向一个vtbl指针,该指针指向虚拟函数表。由于一个COM组件可以支持任意数目的接口,因此对于这类组件,我们使用抽象基类的多重继承实现。 在C语言中,可以通过结构和函数指针配合来实现COM接口。参考《COM原理与应用》的P27。 C++中对一般函数、虚拟函数、成员变量的处理 在C++中,一般函数指针是存放在类中的,归所有实例对象共用。成员变量存放在实例对象中。虚拟函数的指针仍然存放在类中,但在实例对象中存放一个vtbl指针,该指针指向虚拟函数表。虚拟函数表中存放函数指针,每个指针指向类中的函数指针。 通过vt中函数指针,根据类指针的实际类型调用虚拟函数,而不是根据类指针声明的类型调用虚拟函数。 可以参考《COM技术内幕》的P24~26的三张图。 第三章 QueryInterface函数关于IUnknown COM规范中定义了一个IUnknown接口。 interface IUnknown { virtual HRESULT _stdcall QueryInterface(const IID& iid, void **ppv) = 0; virtual ULONG _stdcall AddRef() = 0; virtual ULONG _stdcall Release() = 0; } 其中#define interface struct。HRESULT的介绍在第六章。IID的介绍在第七章。 每个COM接口都直接或间接继承自IUnknown。所以所有接口的vtbl的前三个函数都是QueryInterface,AddRef和Release。 QueryInterface的作用 客户可以通过该函数查询某个组件是否支持特定的接口。组件的IID在id参数中指定,如果找到该接口,则*ppv=接口指针,并且返回S_OK。否则*ppv = NULL,返回E_NOINTETRFACE。 COM规范只定义了该函数的参数、返回值和功能,具体实现则没有定义。MFC、ATL都有自己的实现,书本中作者给出了自己的简单实现。该函数是在COM组件中实现的(不可能是在COM接口中实现,因为接口是纯虚抽象的)。而且COM组件应该知道自己实现了哪些接口,接口是不可能知道的。 书上的实现是通过if-else结构。如果id = IID_xxx,转换this类型到相应的接口指针,返回该指针。 实现QueryInterface的规则 COM规范虽然没有规定QueryInterface如何实现,但规定了一些实现规则。 1. QueryInterface返回的总是同一个IUnknown指针。为了确保两个接口是否指向同一个组件,可以通过这两个接口查询IUnknown接口,然后将返回值进行比较。 2. 若客户获得过某个接口,还能够再次获得这个接口 3. 客户可以再次获得已经拥有的接口。即可以自反。 4. 客户可以返回起始接口 5. 若能从某个接口获取特定接口,则从任意接口都将获得此接口。 接口与IID 每个接口都有一个唯一的接口标识符(IID)。一般情况下,我们不会改变接口,而是建立一个新接口为之指定一个新的IID。当QueryInterface接到对老IID的查询时,返回老的接口;新的IDD则返回新接口。对QueryInterface而言,一个IID就是一个接口。 这种方式可以保证老接口、新接口都能够使用,保证了兼容性。 第四章 引用计数引用计数的作用就是为了控制一个COM组件的生命期。引用计数可以让组件在不再使用的时候自己将自己删除。COM组件维护一个称为引用计数的数值,当客户从组件取得一个接口的时候,引用计数值加1,当客户使用完某个接口之后,组件的引用计数值减1。当引用计数值为0时,组件将自己从内存删除。 COM规范规定AddRef(IUnknown接口的虚拟函数)增加引用计数,Release减少引用计数。 实现引用计数的三个层次 可以在三个层次上实现引用计数 1. 对整个组件DLL使用引用计数。整个组件DLL可能包含多个COM组件。通过一个DLL内的全局变量实现。 2. 对一个COM组件使用引用计数。通过组件内的成员变量实现。 3. 对COM组件的每个接口使用引用计数。通过组件内成员变量实现,对每个接口都有一个用于引用计数的成员变量,或者使用一个数组。 优缺点可以参考《COM原理与应用》的p36。 但无论如何实现引用计数,使用AddRef和Release时,都必须认为组件使用了第三种方式的引用计数实现方法,即接口级的实现方法。这就需要客户应该对它将要使用的那个接口指针调用AddRef,而不是对同一个COM组件的另一个接口指针调用AddRef。否则,如果接口指针实现了。 书上的例子是采用了第二种方法,虽然它建议采用第三种方法。不考虑返回值,AddRef的操作是m_cRef++,Release的操作是if (--m_cRef == 0) delete this; COM规范固定二者的返回值都是一个当前的引用计数值。 调用引用计数的规则 一般有下列调用AddRef和Release的规则: 1. 在返回之前调用AddRef。对于那些返回接口指针的函数埃返回之前必须调用相应的AddRef。这样当客户从这种函数得到一个接口后,无需调用AddRef。 2. 使用完接口后调用该接口的Release。可以保证该接口在不用的时候可以释放掉。 3. 赋值之后调用AddRef。在将一个接口指针赋给另一个接口指针时,应调用AddRef。保证该接口在使用的时候不被释放。 如果严格按照这三条规则,则不会导致内存泄漏(AddRef比Release多)和空指针(Release比AddRef多)。这也是规则的唯一作用。如果能够保证没有内存泄漏和空指针,则也可以不使用这些规则。但比较繁琐。所以又有下面的优化引用计数的经验规则: 1. 输出参数规则 也包括返回值。所以任何在输出参数种或作为返回值返回一个新的接口指针的函数必须对此接口指针调用AddRef。因为返回值和输出参数也是一种赋值方式,者符合标准规则1、3。 2. 输入参数规则 对输入的接口指针,无需调用AddRef和Release。按照前面的规则,输入参数有一个赋值过程,需要AddRef,返回的时候就不再使用该接口指针参数了,需要调用Release。该规则指示二者都不调用,也不会导致引用计数的不一致。 而且因为函数的生命期嵌套在调用者的生命期之内,所以不用担心调用者Release掉传入的接口指针,而导致空指针。 3. 输入-输出参数规则 在参数被修改之前,调用Release;修改之后,调用AddRef。对应标准规则2和3,修改意味着不再使用就接口指针,所以Release;修改意味着一次赋值,所以AddRef。 4. 局部变量规则 类似于输入参数。 5. 全局变量规则 对于保存在全局变量中的接口指针,在将其传递给另一个函数前,必须调用其AddRef。因为此标量时全局性的,任何函数都可以通过调用其Release中止其生命期。对于成员变量中的接口指针,也是同样规则。 第五章 动态链接本章在DLL中实现了COM组件,接口放在.h文件中,客户程序和dll程序共享。DLL只有一个输出函数,用来CreateInstance,即产生组件的IUnknown接口指针。客户程序通过动态导入DLL,然后调用CreateInstance,获得IUnknown指针。因为接口定义的.h文件在客户程序中包含,以后客户程序就可以任意访问接口的方法了。

 

http://www.newsmth.net/pc/pccon.php?id=1363&nid=73476

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值