COM组件的生命期控制

本文探讨了COM组件为何需要提供生命期控制函数,详细解释了COM如何通过接口的引用计数(AddRef和Release)来间接控制组件生命周期。介绍了组件级与接口级引用计数的区别,并列举了引用计数的六条规则,强调了在不同场景下如何正确管理接口的生命期。
一、 提供生命期控制函数的必要性。 到目前为止客户对COM组件知道的仅仅是接口,因此客户也就不能直接控制组件的生命周期。为了客户能够更好的控制组件的生命周期,COM组件提供了一种直接控制单个接口生命周期来间接控制组件生命周期的方法。 二、 生命期控制。 1、 客户不直接控制组件生命期的原因。 在客户的代码中,可能会有若干个指向此组件接口的指针。 例如:客户的一部分通过一个指针使用组件的IX接口,另一部分通过另一个指针使用组件的IY接口,当不在使用IX接口时,可能还在使用IY接口。在这种情况下,当使用完一个接口时另一个接口可能还在被使用,因此组件是不能被释放的。这就很难决定何时释放掉组件。 COM组件采用的方法是,由COM组件提供对每个接口的引用计数控制,即IUnknown接口的AddRef和Release函数。客户通过调用AddRef告诉组件开始使用这个接口,调用Release告诉组件使用完此接口。然后由组件自己决定是否释放组件。 2、 COM组件使用接口级引用计数与使用组件级引用计数。 在用户来看,引用计数处于接口级而不是组件级的原因如下: <1>、方便调试 用户对接口操作时,很容易忘记调用Release函数,这就导致组件不能被释放掉。若采用组件级的应用计数,查找的范围是组件的所有接口;若采用接口级别引用计数查找的范围只需要限制在某个接口。从查找范围上来看采用接口级引用技术能够缩小需要调试的范围。 <2>、资源按需获取 在实现一个接口时可能需要大量的内存和资源。若采用组件级的引用计数,只有当组件的所有接口都不再使用时,才能释放资源(包括早已不再使用的资源);若采用接口级的引用技术当接口不再使用时,此与次接口关联的资源就可以被释放。能够对不需要资源的及时释放,节省资源。 三、 引用计数规则。 1、 输出参数规则(即返回前调用AddRef规则)。 任何在输出参数中或者作为返回值返回一个接口指针的函数必须对此接口调用AddRef。 例如:HRESULT QueryInterface(const IID&, void**)在该函数返回前须调用AddRef。 2、 输入参数规则。 对传入函数的指针,无需调用AddRef和Release,原因是函数的生命期嵌套在调用者的生命期内。 例如: void FinalConstruct(IX* pIX)
### C# 中创建和实现 COM 组件 #### 创建 COM 可见类 为了使 .NET 类能够作为 COM 对象被访问,该类必须标记为 `ComVisible` 属性并设置为 `true`。此外,还需要提供 GUID 来唯一标识这个类及其接口。 ```csharp using System; using System.Runtime.InteropServices; namespace ComComponentExample { [Guid("F9E7A8B0-ECA6-4D5C-AEB2-F3DEADBEEF12")] public interface IMyInterface { string GetMessage(); } [ClassInterface(ClassInterfaceType.None)] [Guid("F9E7A8B1-ECA6-4D5C-AEB2-F3DEADBEEF12")] [ProgId("ComComponentExample.MyClass")] [ComVisible(true)] public class MyClass : IMyInterface { public string GetMessage() => "Hello from COM component!"; } } ``` 上述代码定义了一个名为 `IMyInterface` 的接口以及实现了此接口的具体类 `MyClass`[^1]。 #### 注册 COM 组件 编译后的程序集可以通过命令行工具 regasm.exe 进行注册: ```bash regasm YourAssembly.dll /tlb:YourAssembly.tlb /codebase ``` 这会将组件的信息写入 Windows 注册表,并生成一个类型库文件(.tlb),以便其他应用程序可以引用它。 对于客户端应用来说,在调用之前需要先通过 RegisterTypeForComClients 方法来确保服务器端已准备好接收请求。 #### 使用 COM 组件 一旦成功注册之后,就可以像使用任何标准的 COM 对件一样去实例化此类对象了。例如在 VBScript 或者 PowerShell 脚本里可以直接利用 ProgID (`ComComponentExample.MyClass`) 实例化对象: ```powershell $comObject = New-Object -ComObject ComComponentExample.MyClass Write-Host $comObject.GetMessage() ``` #### 生命周期管理 COM 组件具备灵活的生命期控制机制。当不再需要某个特定实例的时候应当及时释放其占用资源;而这些操作通常由宿主环境自动完成。不过开发者也可以手动干预这一过程以优化性能或者满足特殊需求[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值