1 概述
这里讲的不是COM的实现原理,而是工作原理。即COM组件是如何工作,整个生命周期是如何的。这里只讲述两种COM组件,即进程内组件和本地组件。
2 知识基础
动态链接库(Dynamic-Link Library)DLL。
Windows系统的进程-线程模型。
3 两个角度看COM组件
从调用者(功能使用者)的角度来看COM组件,COM组件是一个抽象的功能对象。你知道它提供了什么功能,但是不需要知道它在哪里提供这些功能的,反正系统会将功能交到你手上。
反过来从实现者(功能提供者)的角度来看就不一样了,你还是要选择一下到时候调用者如何使用你的功能的。一般就是选择你的对象要不要放到调用者的进程中去。而一般的选择就是和调用者共用一个进程,这样线程关系比较简单,调用速度也高。只有特殊的情况下才独立进程,例如做大的系统担心互相影响、或者实现者的生命周期不能被调用者局限、实现者需要做系统单例等情况。
本文档就是写一下调用COM组件的整个流程的简单描述,大家有个大概的认识,方便大家开发实现者。
4 进程内COM组件
所谓进程内COM组件,就是对象创建于调用者进程中的组件,英文名称In-process Server。其形态一般为DLL或OCX。其注册方法是regsvr32(手工),DllRegisterServer(程序),vsdrpCOMSelfReg(安装)。其原理如图所示。
5 本地COM组件
所谓本地COM组件,就是对象创建于与调用者进程同一个系统之中的不同进程之中的组件,英文名称Local Server。其注册方法是带“/regserver”运行(手工/程序),vsdrpCOMSelfReg(安装)。其形态一般为EXE。其原理如图所示。
6 ATL组件
不管是进程内ATL组件还是本地ATL组件,都是按照COM组件的原理,或者说被调用的机制的来实现。具体运行逻辑参见上图,可以看到和COM调用原理一一对应。
在VISIO绘图里面没有说明需要在这里补充的是,各个子功能的实现,如类工厂、类型列表、对象引用、对象与模块类引用计数挂钩、对象信息维护等的实现。一言以蔽之,就是模板类(注意,不是模块类)和代码插入。
ATL7.1开发中,COM对象的类声明前面会有COM类属性声明,根据COM类属性声明(如coclass),ATL会在编译前插入若干代码来实现各种COM框架需要的功能。如根据类的定义插入类工厂的实现,将类的信息放在类型列表的初始化,让类派生于CComObjectRootEx实现对象信息维护。在类工厂的实现中使用CComObject等类型来实现对象引用计数,对象与模板类引用计数挂钩。
这就是ATL7.1(注意,ATL6.0不是)的精髓,将各种基础类做成模板,使用代码插入时就根据COM对象声明选择合适的模板参数。与MFC的ClassWizard相比,因为开发者看不到插入的框架代码,所以无法修改。虽然有个开发灵活性不足的缺点,但是框架稳定性大大加强。