安全中国首页 > 文章中心 > 编释语言
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

《加密解密 技术内幕》 COM 原理与应用

更新时间:2008-4-3 0:19:42
责任编辑:流火
热 点:


-------------------------------------------------------------------------------

   组件程序的装载和卸载

-------------------------------------------------------------------------------

进程内组件的装载:

 

客户程序调用COM 库的 CoCreateInstance 或 CoGetClassObject 函数创建 COM 对象,在 CoGetClassObject 函数中,COM 库根据系统注册表中的信息,找到类标识符 CLSID 对应的组件程序(DLL 文件)的全路径,然后调用 LoadLibrary(实际上是 CoLoadLibrary)函数,并调用组件程序的 DllGetClassObject 引出函数。DllGetClassObject 函数创建相应的类厂对象,并返回类厂对象的 IClassFactory 接口。至此 CoGetClassObject 函数的任务完成,然后客户程序或者 CoCreateInstance 函数继续调用类厂对象的 CreateInstance 成员函数,由它负责 COM 对象的创建工作。

 

  CoCreateInstance

   |-CoGetClassObject

     |-Get CLSID -> DLLfile path

     |-CoLoadLibrary

     |-DLLfile.DllGetClassObject

     |-return IClassFactory

   |-IClassFactory.CreateInstnace

 

进程外组件的装载:

 

在 COM 库的 CoGetClassObject 函数中,当它发现组件程序是 EXE 文件(由注册表组件对象信息中的 LocalServer 或 LocalServer32 值指定)时,COM 库创建一个进程启动组件程序,并带上“/Embedding”命令行参数,然后等待组件程序;而组件程序在启动后,当它检查到“/Embedding”命令行参数后,就会创建类厂对象,然后调用 CoRegisterClassObject 函数把类厂对象注册到 COM 中。当 COM 库检查到组件对象的类厂之后,CoGetClassObject 函数就把类厂对象返回。由于类厂与客户程序运行在不同的进程中,所以客户程序得到的是类厂的代理对象。一旦客户程序或 COM 库得到了类厂对象,它就可以完成组件对象的创建工作。

进程内对象和进程外对象的不同创建过程仅仅影响了 CoGetClassObject 函数的实现过程,对于客户程序来说是完全透明的。

 

  CoGetClassObject

   |-LocalServer/LocalServer32

   |-Execute EXE /Embedding

     |-Create class factory

     |-CoRegisterClassObject ( class factory )

   |-return class factory (proxy)

 

进程内组件的卸载:

 

只有当组件程序满足了两个条件时,它才能被卸载,这两个条件是:组件中对象数为 0,类厂的锁计数为 0。满足这两个条件时,DllCanUnloadNow 引出函数返回 TRUE。COM 提供了一个函数 CoFreeUnusedLibraries,它会检测当前进程中的所有组件程序,当发现某个组件程序的 DllCanUnloadNow 函数返回 TRUE 时,就调用 FreeLibrary 函数(实际上是 CoFreeLibrary 函数)把该组件从程序从内存中卸出。

该由谁来调用 CoFreeUnusedLibraries 函数呢?因为在组件程序执行过程中,它不可能把自己从内存中卸出,所以这个任务应该由客户来完成。客户程序随时都可以调用 CoFreeUnusedLibraries 函数完成卸出工作,但通常的做法是,在程序的空闲处理过程中调用 CoFreeUnusedLibraries 函数,这样做既可以避免程序中处处考虑对 CoFreeUnusedLibraries 函数的调用,又可以使不再使用的组件程序得到及时清除,提高资源的利用率,COM 规范也推荐这种做法。

 

进程外组件的卸载:

 

进程外组件的卸载比较简单,因为组件程序运行在单独的进程中,一旦其退出的条件满足,它只要从进程的主控函数返回即可。在 Windows 系统中,进程的主控函数为 WinMain。

前面曾经说过,在组件程序启动运行时,它调用 CoRegisterClassObject 函数,把类厂对象注册到 COM 中,注册之后,类厂对象的引用计数始终大于 0,因此单凭类厂对象的引用计数无法控制进程的生存期,这也是引入类厂对象的加锁和减锁操作的原因。进程外组件的载条件与 DllCanUnloadNow 中的判断类似,也需要判断 COM 对象是否还存在、以及判断是否锁计数器为 0,只有当条件满足了,进程的主函数才可以退出。

从原则上讲,进程外组件程序的卸载就是这么简单,但实际上情况可能复杂一些,因为有些组件程序在运行过程中可以创建自己的对象,或者包含用户界面的程序在运行过程中,用户手工关闭了进程,那么进程对这些动作的处理要复杂一些。例如,组件程序在运行过程中,用户又打开了一个文件并进行操作,那么即使原先创建的对象被释放了,而且锁计数器也为 0,进程也不能退出,它必须继续为用户服务,就像是用户打开的进程一样。对这种程序,可以增加一个“用户控制”标记 flag,如果 flag 为 FALSE,则可以按简单的方法直接退出程序即可;如果 flag 为 TRUE,则表明用户参与了控制,组件进程不能马上退出,但应该调用 CoRevokeClassObject 函数以便与 CoRegisterClassObject 调用相响呼应,把进程留给用户继续进行。

如果组件程序在运行过程中,用户要关闭进程,而此时并不满足进程退出条件,那么进程可以采取两种办法:第一种方法,把应用隐藏起来,并把 flag 标记设置为 FALSE,然后组件程序继续运行直到卸载条件满足为止;另一种办法是,调用 CoDisconnectObject 函数,强迫脱离对象与客户之间的关系,并强行终止进程,这种方法比较粗暴,不提倡采用,但不得已时可以也使用,以保证系统完成一些高优先级的操作。

 

-------------------------------------------------------------------------------

   COM 库常用函数

-------------------------------------------------------------------------------

初始化函数    CoBuildVersion        获得 COM 库的版本号

              CoInitialize          COM 库初始化

              CoUninitialize        COM 库功能服务终止

              CoFreeUnusedLibraries 释放进程中所有不再使用的组件程序

GUID 相关函数 IsEqualGUID           判断两个 GUID 是否相等

              IsEqualIID            判断两个 IID 是否相等

              IsEqualCLSID          判断两个 CLSID 是否相等 (*为什么要3个函数)

              CLSIDFromProgID       字符串组件标识转换为 CLSID 形式

              StringFromCLSID       CLSID 形式标识转化为字符串形式

              IIDFromString         字符串转换为 IID 形式

              StringFromIID         IID 形式转换为字符串

              StringFromGUID2       GUID 形式转换为字符串(*为什么有 2)

对象创建函数  CoGetClassObject      获取类厂对象

              CoCreateInstance      创建 COM 对象

              CoCreateInstanceEx    创建 COM 对象,可指定多个接口或远程对象

              CoRegisterClassObject 登记一个对象,使其它应用程序可以连接到它

              CoRevokeClassObject   取消对象的登记

              CoDisconnectObject    断开其它应用与对象的连接

内存管理函数  CoTaskMemAlloc        内存分配函数

              CoTaskMemRealloc      内存重新分配函数

              CoTaskMemFree         内存释放函数

              CoGetMalloc           获取 COM 库内存管理器接口

 

-------------------------------------------------------------------------------

   HRESULT 类型

-------------------------------------------------------------------------------

大多数 COM 函数以及一些接口成员函数的返回值类型均为 HRESULT 类型。HRESULT 类型的返回值反映了函数中的一些情况,其类型定义规范如下:

 

   31 30 29 28                    16 15                                0

  |-----|--|------------------------|-----------------------------------|

 

类别码 (30-31) 反映函数调用结果:

                00 调用成功

                01 包含一些信息

                10 警告

                11 错误

自定义标记(29) 反映结果是否为自定义标识,1 为是,0 则不是;

上一页 1 2 3 4 5 6 下一页

 
相关文章
一日一文章
 
一日一软件
一日一动画