聊一聊被 .NET程序员 遗忘的 COM 组件

网站建设4年前发布
23 0 0

最近遇到了好几起和 COM 相关的Dump,由于对 COM 整体运作不是很了解,所以分析此类dump还是比较头疼的,比如下面这个经典的 COM 调用栈。,为了做一个简单的梳理,我们搭建一个简单的多语言 COM 互操作。,可能很多新生代的程序员都不知道 COM ,最多也只听过这个名词,其实在 Windows 上有海量的 COM 组件,这些组件信息都是注册在 HKEY_CLASSES_ROOT\CLSID 节点目录,截图如下:,20230306005528e94967a48248a3524bb5120335bb4c3cadc1c9482,这个和微服务中的 注册中心 是一个道理,这一篇我们用 C# 写一个COM组件,用 C++ 去调用。,写一个 .NET Framework 4.8 下的 32bit  FlyCom 组件,一个接口,一个实现类,具体原理后续再分析,先搭建尝尝鲜, C# 代码如下:,这里简单说一下:,一个是接口(BaseFly) 的唯一码,即 IID 信息, 一个是 COM组件的 唯一码,叫做 CLSID。,因为 GUID 不方便记忆,所以给这个 COM组件 取一个别名叫 FlyCom.Show 。,这个是为了遵循 COM多语言互通下的 vtable调用标准,表示第一个接口方法是 Show,后续再聊。,有了代码,接下来还要做三个配置。,修改 AssemblyInfo.cs 中的 ComVisible = true,参考如下:,一般来说,将 com 放到 注册表,最好都生成一个强签名,否则会有警告提示。,20230306005528c685c695343ccc072cd841ace0e1b9ed1ad460982,在属性面板中,选择 Build 选项卡,选中 Register for COM interop 选项即可。,20230306005803895dd0503ca28880583713ffd22bf8d652951f920,要将 com组件 放到注册表,需要使用注册表编辑工具 regasm。,从输出中可以看到已成功注册,并且生成了一个 FlyCom.tlb 代理文件,接下来可以到注册表中验证一下 GUID=270C3ED3-053D-4324-9176-9C3FA2BE58A7 注册项以及别名为 FlyCom.Show 的注册项。,202303060058522969fd339c23485c1945067fe10b588c073e58128,2023030600553135202e465ed698bedd1612bea37327012d7edf821,要想 C++ 调用 C# 写的 COM 组件,就像 RPC 调用一样,直接自动生成的代理文件即可,将 FlyCom.tlb 复制到 根目录,并且将程序改成 Win32 位,截图如下:,2023030600553281b501a97172f11af85744b3cb1a0c199229b8868,接下来就是完整的 C++ 代码。,将程序跑起来后,真的很完美。,20230306005532984acc72053facc6ea57450a0b03070362c388111,从 C++ 调用 COM 的流程图可以很清楚的看到,这是面向接口编程的方式,非常完美。,千言万语不及一张图。,20230306005533862faa99174e756b5d2755e56c386082beb898936,这就是 COM 能够实现多语言互通的规范,熟悉 C++ 的朋友肯定知道 vtable ,C++ 能够实现多态,全靠这玩意,COM 也是用了 vtable 这套模式,所以诸如 JAVA,C#,VBS 必须在二进制层面将代码组织成上图这种形式,才能实现 COM 的互通。,所以在 C# 中你看到的 DispId 特性就是为了按照 vtable 方式进行组织,对于 ole32 和 combase 这些 COM 运行环境的基石,我们后续用 windbg 来解读一下,这一篇就先到这里,希望对你有帮助。

© 版权声明

相关文章