正在学习COM原理与应用,怕自己忘记,所以做了以下笔记
一、COM接口简介
1. 二进制特性:接口规范不建立在任何编程语言的基础上,而是规定了二进制一级的标准。任何语言只要有足够的数据表达能力,就可以对接口进行描述,从而可以用于与组件程序有关的应用开发。
2.接口不变性:接口是组件客户程序和组件对象之间的桥梁,接口如果经常发生变化,则客户程序和组件程序也要跟着变化,这对于应用系统的开发非常不利,也不符合组件化程序的设计思想。
3.继承性(扩展性):COM接口具有不变性,但不变性不意味着不再发展,随着应用系统和组件程序的不断发展,接口也需要发展。类似于C++中类的继承性,接口也可以继承发展,但接口继承和类继承不同。首先,类继承不仅是说明继承,也是实现继承,既派生类可以继承基类的实现,而接口继承只是说明继承。其次,类继承允许多重继承。一个派生类可以有多个基类,但接口继承只允许单继承,不允许多重继承。
根据COM规范,所有的接口必须由IUnknown派生,可以是直接派生,也可以是间接派生。
所有接口都必须继承lUnknown继承的原因在于IUnknown提供了两个非常重要的特性:生存周期控制(引用计数)和接口查询。客户只能通过接口与COM对象进行通信,虽然客户程序不用管对象内部的实现细节,但它要控制对象的存在与否。另一方面,如果一个COM实现了多个接口,在初始时刻,客户程序不太可能得到该对象的所有接口指针
4.多态性(运行过程的多态性):多态是面向对象系统的重要特性,COM对象也具有多态性,其多态性通过COM接口体现。多态性使得客户程序可以用统一的方法处理不同的对象,甚至是不同类型的对象,只要他们实现了同样的接口。
正是由于COM的多态性,我们才可以用COM规范建立插件系统,应用程序可以用统一的方法处理每一个插件。
COM组件分类:进程内组件(DLL) + 进程外组件(EXE)
进程内组件:进程内组件与客户程序运行在同一进程地址空间中,一旦客户程序与组件程序建立起通信之后,客户程序得到的接口指针直接指向组件程序中接口的vtable包括了所有接口成员函数的地址 ,客户程序可以直接调用些组件程序的成员函数,所以其效率非常高。
以编制DLL程序时,对于每一个引出函数,使用extern ''c'说明符(保证通用性),以及加上_stdcall修饰符(函数参数地址空间由被调用函数回收),或者写def文件
extern "c" int _stdcall MyFunction(int n);
extern "c" _declspec(dllexport) int _stdcall MyFunction(int n);(win32平台上,说明函数为引出函数)
注:DLL不仅可以引出函数,还可以引出全局变量
进程外组件:组件程序独占一个进程,运行在客户程序的外面,称为进程外组件或进程外服务程序。
因为客户程序与组件不在一个地址空间,,所以组件与客户之间的通信必须跨越进程边界。COM采用本地过程调用(local procedure call LPC ) 和 远程过程调用(Remote procedure call RPC)的方法进程进程间的通讯 。
代理DLL和存根DLL除了完成LPC调用之外,它还需要对参数和返回值进行翻译和传递。如果组件程序与客户程序运行在不同的机器 上,则代码DLL和存根DLL就得通过RPC方式进行网络上的过程调用,从而实现分布式组件对象模型。
组件程序的开发者除了得实现组件程序外,还得实现代表DLL和存根DLL两个程序模块,它们只负责接口成员函数调用过程中的中间处理工作,所以应该针对接口实现代理DLL和存根DLL;如果使用的是COM预定义的标准接口或者OLE接口,则可以直接使用系统提供的DLL,COM库会为我们处理中间细节。
二、COM对象是通过注册表来管理
COM规范使用128位GUID来标识COM对象的接口,客户程序通过这些GUID值来创建COM对象并与对象进行交互。因为客户程序和组件程序是独立的,客户程序在创建组件程序的时候并不知道组件程序的确切位置,按照COM规范,客户程序通过COM库完成这些对象的创建工作。COM库通过系统注册表所提供的信息进行组件的创建工作。
系统注册表是全系统范围内的信息仓库,其中包含了所有COM组件必要的所有信息以及其它一些信息,COM只用于其中一部分。客户程序和组件程序都可以对系统注册表进行访问。
组件程序把所实现的COM对象的信息以及接口信息都保存到注册表中,这个步骤叫做组件的注册。
COM有关的信息在HKEY_CLASSES_ROOT键下的CLSID子键、Interface子键和TypeLib子键。在CLSID下列出了当前机器上所有组件信息。CLSID子键包含的InprocServer32子键下的缺省值为组件程序全路径文件名和其它信息等。Interface子键给出了当前系统中一些COM接口的配置信息(如果接口为进程外组件,那么针对该接口,必须配有相应的代理DLL和存根DLL,这些信息被保存在Interface子键下的ProxyStubClsid or ProxyStubClsid32子键)。TypeLib子键给出了当前系统中类型库的信息。
一个COM对象可以共CLSID或ProgID(程序标识符)来标识(HKEY_CLASSES_ROOT子键下)
COM提供了两个API用于两者之间的转换:CLSIDFromProgID & ProgIDFromCLSID
COM提供了在注册表中对COM组件进行分类的机制,如果COM组件支持同样一组接口,则把它们分为同一类中,一个组件对象可以被分到多个类中(COM对象可以实际类别中指定的必须要实现的接口外,还可以实现其它的接口),并用CATID描述(在CLSID键下的Implemented Categories子键下)。
在HKEY_CLASSES_ROOT键下的Component Categories子键包含了当前机器所有的组件类别,其中列出了每个组件类别的CATID。
组件类别最主要的用处在于客户可以快速发现机器上特定类别的组件对象,以节省查询过程。
COM组件的注册操作
当组件程序被安装到机器上后,必须通过某种途径把它的信息注册到注册表中,然后客户程序才能根据注册表的信息对组件对象进行操作。根据组件注册能力的不同,分为自注册组件程序和非自注册组件程序 。对于非自注册组件程序,其注册过程和组件程序没有直接关系,必须单独进行注册信息的配置。
进程内组件程序由于不能直接运行,所以必须被某个进程调用才能获得控制(非自注册组件程序)。进程外组件程序可以直接运行,在运行过程中可以完成自身的注册操作(自注册组件程序)。
进程内组件程序的注册方法
1. 注册进程内组件程序的实用工具:RegSvr32.exe,只要进程内组件提供相应的入口函数,则RegSvr32.exe就可以完成注册和注销操作(DllRegisterServer & DllUnregisterServer)。
例:DLL名称为DictComp.dll
注册:RegSvr32 路径\DictComp.dll //直接调用DLL注册函数DllRegisterServer
注销:RegSvr32 /u 路径\DictComp.dll //直接调用DLL注销函数DllUnregisterServer
2. 利用一些安装程序在安装或卸载过程中调用组件程序中的DllRegisterServer 和 DllUnregisterServer函数完成组件的注册和注销。
进程外组件程序的注册方法
由于进程外组件程序自身是可执行程序,而且不能提供入口函数供其它程序调用,因此COM规范中规定,支持自注册的进程外组件程序必须支持两个命令行参数/RegServer 和 /UnregServer,以便完成注册和注销操作。

本文介绍了COM(Component Object Model)的核心概念,包括COM接口的二进制特性、不变性、继承性和多态性。COM接口作为组件与客户程序间的桥梁,允许不同语言的互操作性。COM组件分为进程内(DLL)和进程外(EXE)两种,通过注册表进行管理,并使用GUID标识。注册组件通常涉及DLLRegisterServer和DllUnregisterServer函数,以及自注册组件的/RegServer和/UnregServer命令行参数。
&spm=1001.2101.3001.5002&articleId=38079329&d=1&t=3&u=691b5930f7a84cca94c67d782bb73709)
4822

被折叠的 条评论
为什么被折叠?



