COM道理与应用—-COM的实现
副标题#e#
1、COM的实现与操纵系统平台密切相关
因为COM最初源于Microsoft Windows平台,所以COM实现部门(即COM库)许多处所直接用到了Windows系统的一些特性,好比系统注册表、动态毗连库等等,但实际上 COM是一个与平台无关的组件软件模子。Windows上利用的COM尺度只是COM的一个详细实现。
2、COM的实现要领
历程内组件(DLL ,in-process component)。
历程外组件(EXE ,out –of-process component)。
3、DLL措施的建设要领
(1)建设一个DLL工程
(2)建设DLL时,应该利用_stdcall挪用习惯引出函数,并利用extern “C”说明符。这样可以或许担保与其他编译器和编程语言的兼容。
(3)凭据传统的编程要领,编写一个DEF文件,用来描写DLL措施的模块信息,即列出所有引出函数,并给每个引出函数分派一个独一的序号。在Win32平台上,可以不利用DEF文件,而直接在函数说明时利用_declspec(dllexport)说明符,如下:
extern “C” _declspec(dllexport) int _stdcall MyFunction();
4、客户措施操纵DLL措施的三个系统函数
LoadLibrary,装载DLL模块函数
GetProcAddess,取引出函数地点的函数
FreeLibrary,释放DLL措施的函数
5、DLL的三点说明
(1)对付历程内组件,因为客户措施与DLL措施在同一个地点空间,所以,DLL措施不只可以引出函数,也可以引出全局变量。
(2)VC++提供了利用东西DumpBin,通过/EXPORTS选项可以列出DLL措施中的所有被引出的信息。(实际运行中需要LINK.EXE和MSPDB60.DLL的支持)
(3)假如客户措施自己也是一个DLL措施,,则它必然要先被装入到历程空间中。
6、历程外组件与客户通信跨跃历程界线协同事情
(1)两个问题
一个历程如何挪用另一个历程中的函数。
参数如何从一个历程被通报到另一个历程中。
(2)Windows平台上差异历程间通信的要领
动态数据互换(DDE)
定名管道(named pipe)
共享内存
#p#副标题#e#
(3)COM回收的历程间通信的要领
当地进程挪用(LPC,local procedure call),用在同一呆板的差异历程间的通信。
远进程挪用(RPC),用于差异呆板间的历程间通信。
跨历程通信是操纵系统实现的重要部门,并且,在系统底层实现跨历程操纵更为便利,因为在系统一级,它可以节制应用历程的资源分派,包罗逻辑内存空间到物理内存的映射、CPU时间的调治等。从节制本领来讲,操纵系统可以挪用任何一个历程中的函数。
(4)应用措施挪用其他历程中系统处事的进程
上图的挪用进程中涉及到跨历程操纵,实际上也就是用到LPC。应用A实际上挪用的是系统模块DLL,其称为存根(stub)模块。
(5)客户措施和历程外组件之间的挪用干系
历程外组件较历程内组件的效率要低,但在跨历程的挪用中也为客户措施带来了安详性。在署理DLL和存根DLL之间的通信是通过列集和散集(对参数和返回值举办翻译和通报)操纵来完成的。
假如只思量客户措施和组件措施,那么工作就简化的多了,客户措施挪用接口成员函数就仿佛是直接举办的,如上图虚线所示。凭据这样简化的布局,历程外组件和历程内组件就有了一致的模子了,COM正是通过这种方法实现历程模子的透明特性的。假如组件措施运行在差异的呆板上,则署理DLL和存根DLL就通过RPC方法举办网络上的进程挪用,从而实现漫衍式组件工具模子,所有这些特性的实现可以完全成立在操纵系统提供的LPC和RPC模块基本上,而不需要应用系统开拓人员去思量这些底层的细节技能问题。
(6)历程外组件的实现
除了实现组件措施外,还应给实现署理DLL和存根DLL两个措施模块,它们只与 COM接口有关,只认真接口成员函数挪用进程中的中间处理惩罚事情。假如利用自界说的COM接口,则应该成立本身的DLL措施;假如利用COM预界说的尺度接口可能OLE接口,则可以直接利用系统提供的DLL,COM库会为我们处理惩罚这些细节。
7、通过注册表打点COM工具
凡是,组件工具的建设事情由COM来完成,COM库通过系统注册表(systrm registry)所提供的信息举办组件的建设事情。
8、COM组件注册信息
注册表布局与COM库是直接相关的,实现COM库时必需同时界说出注册表的布局。在Windows平台上,COM库所要求的注册信息都被放到其注册表中。RegEdit.exe可以用来编辑注册表。
COM组件信息在HKEY_CLASSES_ROOT的CLSID下。若是历程内组件,则组件的CLSID子键下包括了InprocServer32子键;若是历程外组件,则组件的CLSID子键下包括了LocalServer32子键,它们的缺省值为组件措施的全路径文件名。与CLSID同一层上,Interface子键给出了当前系统中一些COM接口的设置信息,TypeLib子键给出了当前系统中范例库的信息。署理DLL和存根DLL的信息别离生存在CLSID下的ProxyStubClsid或ProxyStubClsid32子键下。CLSID下的ProgID(program identifier ,措施标识符)子键记录了组件工具的类标识符,COM提供了两个API函数CLSIDFromProgID和ProgIDFromCLSID,用于在 128位正数值和类标识符之间转换。
#p#分页标题#e#
COM提供了在注册表中对COM组件举办分类的机制,分类的道理很简朴,假如COM组件支持同样的一组接口,则可以把它们分到统一类中,一个组件工具可以被分到多个类中。
种别信息也用一个GUID来描写,称为CATID。种别特性只是COM工具的部门特性,假如COM工具要插手到某个种别中,则它必需实现该种别指定的多有接口。在HKEY_CLASSES_ROOT键下有一个子键“Component Gategories”,包括了当前呆板上所有的组件种别,个中列出了每个组件类此外CATID。用VC++提供的OleView.exe东西可以看到种别信息。
9、COM组件的注册操纵
当组件措施被安装到呆板上之后,必需通过注册才气使客户措施通过注册表利用它。历程内组件不能直接运行,所以必需通过其他历程挪用才气得到节制,而历程外组件可以直接运行,可以在执行进程中完成自身的注册操纵。Windows系统东西RegSer32.exe,可用于注册历程内组件,大需要历程内组件提供相应的进口函数DllRegisterServer和DllUnregisterServer。
10、客户措施如何利用组件措施
客户措施并不像第二章中那样直接挪用组件措施的引出函数CreateObject,而是挪用COM库的函数举办组件工具的建设事情,COM库的建设函数按照注册表的信息并挪用组件措施的进口函数来建设组件工具。组件措施需要提供一个尺度的进口函数DllGetObjectClass,用于提供本组件措施的组件信息。
11、类厂
类厂可称为“工具厂”,因为类厂是COM工具的出产基地,COM库通过类厂建设COM工具。对应每一个COM类,有一个类厂专门用于该COM类的工具建设操纵。类厂自己也是一个COM工具,它支持一个非凡的接口:IClassFactory。
接口IClassFactory的成员函数CreateInstance用于建设对应的COM工具,LockServer用于节制组件的保留周期。
12、类厂的利用
因为类厂自己也是一个COM工具,用于其他COM工具的建设进程。它由引出函数DllGetObjectClass建设,DllGetObjectClass函数并不是COM库函数,而是由组件措施实现的引出函数。
COM库在接到工具建设的指令后,它要挪用历程内组件的DllGetObjectClass函数,由该函数建设类厂工具,并返回类厂工具的接口指针,COM库可能客户一旦有了类厂的接口指针,它们就可以通过类厂接口IClassFactory的成员函数CreateInstance建设相应的 COM工具。
13、COM库与类厂的交互
在COM库中,有三个API函数可用于工具的建设,它们别离是CoGetClassObject、CoCreateInstance和 CoCreateInstanceEx。凡是环境下,客户措施挪用个中之一完成工具的建设,并返回工具的初始化接口指针。COM库与类厂也通过这三个函数举办交互。
COM工具是历程内组件工具:CoGetClassObject挪用DLL模块的DllGetClassObject引出函数,把参数clsid、iid 和ppv传给DllGetClassObject函数,由DllGetClassObject建设类厂,并返回类厂工具接口指针。
COM工具是历程外组件工具:景象巨大得多。首先CoGetClassObject函数启动组件历程,然后一直期待,直到组件历程把它支持的COM类工具的类厂注册到COM中,于是,CoGetClassObject函数把COM中相应的类厂信息返回。因此,组件外历程被COM库启动时(带呼吁行参数 “/Embedding”),它必需把所支持的COM类的类厂工具通过CoRegisterClassObject函数注册到COM中,以便COM库建设 COM工具利用。当历程退出时,必需挪用CoRevokeClassObject函数以便通知COM它所注册的类厂工具不再有效。组件措施挪用 CoRegisterClassObject函数和CoRevokeClassObject函数必需配对,以担保COM信息的一致性。
关于三个建设工具的函数的选择:
(1)假如建设长途工具可能但愿一次得到工具的多个接口指针,则选用CoCreateInstanceEx函数。
(2)假如但愿获取类厂工具可能要挪用类厂的某些成员函数,则选用CoGetClassObject函数,以便得到类厂工具,并对类厂工具举办操纵。
(3)在其他环境下,利用CoCreateInstance函数建设工具,这是最常用的要领。
14、CoGetClassObject与组件措施的交互进程的例子
用以说明在COM工具建设进程中,客户措施、COM库和历程内组件措施三者之间的顺序干系。
15、类厂对组件保留期的节制
#p#分页标题#e#
类厂是一个COM工具,但凡是只把它看成建设其他组件工具的手段,一般环境下,客户措施可能COM库只是在建设组件工具的时候才利用类厂工具的接口指针,建设完成后就把类厂工具扬弃掉。假如用户但愿保存类厂的接口指针继承利用,则在类厂中引入锁计数来节制组件措施的保留周期。
16、COM库
COM库在整个COM工详细系中起了很重要的浸染。COM除了界说了组件措施和客户措施交互的类型以外,它也提供了COM的实现部门即COM库,使得这些类型可以或许被真正地应用起来。而且,COM库也充当了组件措施和客户措施之间的桥梁,尤其是在组件工具的建设进程中,以及在工具打点、内存打点和一些尺度化操纵等方面起着重要的浸染。
在客户措施和组件措施成立起协作干系之前,它们之间的通信只能靠COM库来通报,而且组件措施和客户措施都大概要用到COM库提供的各类处事。
17、COM库的初始化与卸载
COM库的初始化函数是CoInitialize,其参数pMalloc用于指定一个内存分派器,它是一个IMalloc指针接口,可由应用措施指定内存分派原则。一般将pMalloc设为NULL,由COM库将利用缺省提供的内存分派器。
一个历程对COM库只需要(也必需)举办一次初始化。在乐成初始化并利用完COM库后,必需挪用COM库的终止函数CoUninitialize。但有一个函数的挪用不需要COM库的初始化与卸载,就是CoBuildVersion,该函数用于获取COM库版本。
18、COM库的内存打点
(1)内存利用的两种环境:一种是在客户措施和组件措施成立协作干系之前,靠COM库举办通信,COM需要申请内存,内存不必然是COM库自己利用,也大概是它替组件措施申请并提交出来的;另一种环境是,因为客户措施通过接口指针对组件措施举办操纵,固然这种挪用大概是直接举办的,但组件措施申请的内存有大概由客户措施来释放,所以,在COM库和组件措施、客户措施之间需要有统一的内存打点步伐。
(2)COM库不只提供了这样的内存打点器,还提供了内存打点器的尺度,应用措施可以凭据COM类型指定的尺度成立自界说内存打点器,以代替COM库的缺省内存打点器。
(3)在COM库初始化乐成之后,不管是利用缺省内存打点器照旧利用自界说的内存打点器,应用措施都可以利用COM库举办内存分派或释放,为此,COM库提供了两种操纵要领:
A、直接利用IMalloc接口指针。在客户措施可能组件措施中挪用COM库函数CoGetMalloc,通过IMalloc接口指针和CoGetMalloc函数实现内存打点的统一。
B、COM库封装了三个API函数,可用于内存分派和释放:CoTaskMemAlloc、CoTaskMemRealloc、 CoTaskMemFree。这三个函数别离对应于IMalloc的三个成员函数:Alloc、Realloc和Free,参数的界说也完全一致。
(4)COM库的两种内存打点器:CoGetMalloc函数可用来获取COM库的内存打点器。一种是在初始化时指定的内存打点器可能其内部缺省的打点器(即功课打点器,task allocator),这种打点器在本历程内有效;另一种是跨历程的共享分派器,由OLE系统提供,它可在一个历程内分派内存并传给第二个历程,在第二个历程内利用此内存甚至释放掉此内存。
19、组件措施的装载和卸载
COM库对组件措施的装载和卸载举办节制。客户措施是在运行时刻与组件措施成立毗连的,并且,一旦毗连起来今后,客户措施和组件措施的通信是直接举办的,并不需要COM库的参加,但组件措施的装载是在客户建设第一个组件工具时举办的,组件措施的卸载是在最后一个组件工具被释放之后举办的,这两个行动并不由客户措施直接完成,而是在COM库中完成的。
历程内组件的卸载满意的两个条件:组件中工具数为0,类厂的锁计数器为0。客户措施挪用CoFreeUnusedLibraries函数完成卸载事情。
历程外组件的卸载较量简朴,因为组件措施运行在单独的历程中,一旦退出的条件满意,它只要从历程额主控函数返回即可。在Windows系统中,历程的主控函数为WinMain。类厂工具的引用计数无法节制历程的保留期,所以引入类厂工具的加锁和减锁操纵。
20、COM库的常用函数
在COM库中还给出了很多尺度接口的界说,譬喻IUnknown、IClassFactory、IMalloc。
21、HRESULT范例
在COM中大大都的函数以及一些接口成员函数的返回值范例均为HRESULT范例。HRESULT范例的返回值反应了函数挪用进程中的一些环境,并且HRESULT范例界说也有必然的类型。
#p#分页标题#e#
HRESULT并不是指向功效布局的句柄,而是一个32位整数,凡是被界说为DWORD或long范例。HRESULT的32位被分成四个域:种别码(30-31)、自界说符号位(29)、操纵码(16-28)、操纵功效码(0-15)。
Win32 SDK的头文件WinError.h界说了Win32函数所有的大概返回功效,个中也包罗了COM库函数以及OLE函数的返回值的宏界说。Win32 SDK提供的FormatMessage函数可按照功效值得到一个对应于该功效值的尺度说明字符串,它也支持COM库函数的返回功效信息。
一般推荐在利用HRESULT范例作为引出函数可能作为接口成员函数的返回值时,只管利用COM可能Win32提供的尺度界说。
22、COM的实现是COM客户措施、COM库和COM组件措施三者之间通过COM拟定的类型协同事情来完成的,三者之间形成了一个统一的整体。
23、第二章的字典组件措施是一个模仿组件措施,第三章的字典组件措施是真正的COM组件措施,这样,在运行客户措施之前必需先注册组件措施,呼吁行为:regsvr32.exe …DictComp.dll 。