Com 组件的装载和卸载 .

来源:互联网 发布:立邦工作知乎 编辑:程序博客网 时间:2024/06/14 07:29
 

进程内组件的装载:



客户程序调用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 则不是;

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝客服不说话也不发货怎么办 面对不说话的客人怎么办? 卖家客服不回复怎么办 2周小孩说话结巴怎么办 微信群里只领红包不说话的人怎么办 躺在微信不说话的客户怎么办 9岁儿童说话结巴怎么办 5岁儿童说话结巴怎么办 京东客服不说话怎么办 两岁宝宝说话有点结巴怎么办 孩子不敢跟外人说话怎么办? 孩子不爱跟外人说话怎么办 别人说我不说话怎么办 衣服屁股那块变亮怎么办 小孩家里说话外面不说话怎么办 2个月小宝宝便秘怎么办 3个月小宝宝便秘怎么办 微信客户不说话怎么办 一岁半宝宝便秘肛裂怎么办 网恋现在都不说话了怎么办 宝宝便秘四天了怎么办 月子里小孩吐奶怎么办 月子里的小孩吐奶怎么办 婴儿吃多了吐奶怎么办 20个月孩子便秘怎么办 一岁宝宝肛裂怎么办 婴儿吃饱了吐奶怎么办 23天新生儿吐奶怎么办 婴儿吐奶舌苔白怎么办 宝宝吐奶酸臭味怎么办? 1周岁吐奶有酸味怎么办 十多天的宝宝吐奶怎么办 未满月婴儿吐奶怎么办 2个月宝宝溢奶怎么办 四岁宝宝说话结巴怎么办 小孩说话结巴打顿怎么办 2岁宝宝突然说话结巴怎么办 2岁宝宝突然结巴怎么办 幼儿舌头起泡牙龈出血怎么办 小孩长得太快怎么办 脑出血压着神经不会说话怎么办