com里的代理存根库,是怎么被com库找到的?

3 com里的代理存根库,是怎么被com库找到的?


在 COM(Component Object Model)中,代理存根(Proxy-Stub)库的作用是实现跨进程(或跨机器)接口调用的参数序列化(Marshal)和反序列化(Unmarshal)。当客户端调用远程对象的方法时,COM 库需要找到并加载对应的代理存根库,以确保接口参数的正确传递。以下是其工作原理:


1. 接口与代理存根的注册关系

COM 通过注册表(Registry)管理接口(Interface)和对应的代理存根库之间的映射关系。关键步骤如下:

(1) 接口定义 (IID) 的注册
  • 每个 COM 接口都有一个唯一的 IID(Interface Identifier),例如 IID_IMyInterface
  • 在注册表中,接口的 IID 会注册在路径:
    HKEY_CLASSES_ROOT\Interface\{IID}
    例如:
    HKEY_CLASSES_ROOT\Interface\{00000001-0000-0000-C000-000000000046}\
    
(2) 代理存根的 CLSID 绑定
  • 在接口的注册表项下,存在一个子键 ProxyStubClsid32(或 ProxyStubClsid,取决于系统位数)。
    例如:
    HKEY_CLASSES_ROOT\Interface\{IID}\ProxyStubClsid32
    (Default) = {ProxyStub_CLSID}
    
  • 这里的 ProxyStubClsid32 值指向一个 CLSID,即代理存根库的类标识符。

2. 代理存根库的 CLSID 到 DLL 的映射

  • COM 根据 ProxyStubClsid32 找到对应的 CLSID 后,会进一步在注册表中查找该 CLSID 对应的 DLL 路径:
    HKEY_CLASSES_ROOT\CLSID\{ProxyStub_CLSID}\InProcServer32
    (Default) = "C:\Path\to\YourProxyStub.dll"
    
  • 这个路径指向代理存根库的 DLL 文件。

3. COM 库加载代理存根库

  1. 客户端调用远程接口方法时,COM 运行时发现需要跨进程/跨机器通信。
  2. 查询注册表:通过接口的 IID,找到关联的代理存根 CLSID。
  3. 加载 DLL:根据 CLSID 对应的 InProcServer32 路径,加载代理存根库(DLL)。
  4. 创建代理对象:在客户端进程中创建代理(Proxy),负责将参数序列化并转发到服务端。
  5. 服务端存根处理:服务端进程中的存根(Stub)接收数据,反序列化后调用实际对象的方法。

4. 特殊情况

  • 系统内置代理存根:某些标准接口(如 IUnknownIDispatch)的代理存根由系统(ole32.dllrpcrt4.dll)直接提供,无需额外注册。
  • 自定义代理存根:开发者需通过 IDL(Interface Definition Language)定义接口,编译生成代理存根代码,并编译为 DLL 后注册到系统。
  • 类型库(TypeLib):若接口使用通用调度(Automation),可能通过类型库的 marshal 关键字自动生成代理存根。

5. 关键工具与流程

  • IDL 编译:使用 MIDL(Microsoft Interface Definition Language Compiler)生成代理存根代码。
  • 注册 DLL:通过 regsvr32.exe 注册代理存根库(调用其 DllRegisterServer 函数)。
  • 调试工具:使用 OleViewRegistry Editor 检查接口和代理存根的注册是否正确。

总结

COM 库通过注册表中的 IID → ProxyStubClsid32 → CLSID → InProcServer32 链,定位并加载代理存根库。这一机制使得跨进程/跨机器的接口调用对开发者透明,只需确保代理存根库正确实现并注册即可。

代理存根的 CLSID 绑定

在接口的注册表项下,存在一个子键 ProxyStubClsid32(或 ProxyStubClsid,取决于系统位数)。
例如:
复制

HKEY_CLASSES_ROOT\Interface\{IID}\ProxyStubClsid32
(Default) = {ProxyStub_CLSID}

这里的 ProxyStubClsid32 值指向一个 CLSID,即代理存根库的类标识符。

这个对应关系,在哪注册到注册表里的?


在 COM 中,代理存根(Proxy-Stub)的 CLSID 绑定关系(即接口 IID 到代理存根 CLSID 的映射)是通过以下两种方式注册到系统注册表中的:


1. 自动注册(通过 regsvr32 注册代理存根 DLL)

当开发者编译代理存根库(例如 YourProxyStub.dll)后,会调用 regsvr32.exe 工具注册该 DLL。此操作会触发 DLL 的 DllRegisterServer 函数,该函数负责将以下信息写入注册表:

(1) 注册接口的 IID 与代理存根 CLSID 的绑定关系
  • 代理存根库的代码中会包含一个 .rgs 脚本文件(由 MIDL 生成),该脚本定义了如何将接口的 IID 与代理存根 CLSID 绑定。例如:
    HKCR {
      Interface\{IID_YourInterface} {
        ProxyStubClsid32 = s '{ProxyStub_CLSID}'
      }
    }
    
  • DllRegisterServer 执行时,会根据 .rgs 脚本在注册表中创建如下键值:
    HKEY_CLASSES_ROOT\Interface\{IID_YourInterface}\ProxyStubClsid32
    (Default) = "{ProxyStub_CLSID}"
    
(2) 注册代理存根 CLSID 的 DLL 路径
  • 同时,代理存根库的 .rgs 脚本也会注册其自身的 CLSID 和 DLL 路径:
    HKCR {
      CLSID\{ProxyStub_CLSID} {
        InProcServer32 = s '%MODULE%'  // 自动替换为 DLL 的完整路径
      }
    }
    
  • 注册后,注册表中会生成:
    HKEY_CLASSES_ROOT\CLSID\{ProxyStub_CLSID}\InProcServer32
    (Default) = "C:\Path\to\YourProxyStub.dll"
    

2. 手动注册(通过 IDL 和 MIDL 生成)

如果开发者使用 IDL(Interface Definition Language) 定义接口,并通过 MIDL(Microsoft IDL Compiler) 生成代理存根代码,MIDL 会自动生成以下内容:

(1) 自动生成注册表脚本
  • MIDL 编译 IDL 文件时,会生成一个 YourProxyStub.rgs 文件,其中包含注册接口 IID 和代理存根 CLSID 的脚本。
  • 例如,对于如下 IDL 定义:
    [
      uuid(IID_YourInterface),  // 接口的 IID
      helpstring("Your Interface"),
      proxyStubClsid(ProxyStub_CLSID)  // 显式指定代理存根的 CLSID
    ]
    interface IYourInterface : IUnknown { ... }
    
    MIDL 生成的 .rgs 文件会包含 ProxyStubClsid32 的注册逻辑。
(2) 编译后的注册流程
  • 开发者编译生成的代理存根代码后,调用 regsvr32.exe 注册 DLL,此时 MIDL 生成的 .rgs 脚本会被执行,自动写入注册表。

3. 系统内置代理存根的注册

对于系统内置接口(如 IUnknownIDispatch),它们的代理存根 CLSID 绑定关系已由 Windows 在系统安装时预先注册,无需开发者干预。例如:

  • IUnknown 的代理存根由 ole32.dll 直接实现。
  • 注册表路径:
    HKEY_CLASSES_ROOT\Interface\{00000000-0000-0000-C000-000000000046}\ProxyStubClsid32
    (Default) = "{00000320-0000-0000-C000-000000000046}"
    

4. 关键验证步骤

如果代理存根未正确注册,可通过以下方式检查:

  1. 检查接口的 ProxyStubClsid32 值是否存在
    reg query HKCR\Interface\{IID_YourInterface}\ProxyStubClsid32
    
  2. 检查代理存根 CLSID 的 DLL 路径是否正确
    reg query HKCR\CLSID\{ProxyStub_CLSID}\InProcServer32
    
  3. 使用工具验证
    • 使用 OleView(OLE/COM Object Viewer)查看接口的代理存根信息。
    • 使用 regsvr32.exe 重新注册代理存根 DLL。

总结

  • 自动注册:通过 regsvr32.exe 调用代理存根 DLL 的 DllRegisterServer 函数,执行 MIDL 生成的 .rgs 脚本,将接口 IID 与代理存根 CLSID 的绑定关系写入注册表。
  • 手动生成:开发者通过 IDL 定义接口并指定 proxyStubClsid,MIDL 生成对应的注册表脚本。
  • 系统内置:Windows 预先注册了标准接口的代理存根。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金士顿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值