阻止 COM 激活服务器可执行文件



TL;DR- 如何防止CLSCTX_LOCAL_SERVER服务器启动-Embedding?最好是让客户端立即获得一个体面的错误代码。

背景

我们有一个本机C++交互式桌面应用程序,该应用程序与另一个本机C++交互式桌面应用程序中的 COM 对象进行交互。

基本上,COM 用作进程间通信机制。

现在,当用户将"服务器"应用程序置于正确状态后以交互方式启动时,它将准备COM接口:CoRegisterClassObject等。

当使用客户端应用程序,然后为coclassCoCreateInstance时,它将与已经在运行的其他桌面应用程序进行通信,这是预期的。

但是,当"服务器"应用程序未运行时,启动客户端将以交互方式启动服务器应用程序,这不是我们想要的,因为它需要相当多的处理和设置才能使客户端有意义地与之通信。

问题

因此,更有意义的是客户端在服务器未运行时出错,而不是让 COM 基础结构启动一个交互式应用程序,该应用程序无论如何都无法有意义地为请求提供服务。

我们考虑了以下想法:

  • 每次关闭服务器时取消注册服务器。
    • 这似乎行不通,因为我们需要管理权限来注册/注销服务器。
  • 使用客户端上的CLSCTX_DISABLE_AAA标志。
    • 这似乎有效,如果客户端指定了这一点并且服务器没有运行,它将0x80070005 ERROR_ACCESS_DENIED,但我们不确定这是否是正确的方法。
  • 服务器应用程序中进行早期检查以检测-Embedding开关,并立即退出应用程序。
    • 客户端应用程序将运行超时(~2 分钟),这不是很用户友好。
  • 从评论不要将信息写入注册表 -CoRegisterClassObject应该就足够了。
    • 目前,我有:
      • HKCRAppID (...)
      • HKCRCLSID{...}加上子项ProgIDVersionIndependentProgIDLocalServer32Typelib
    • 客户端当前从 VersionIndependentProgID 解析 CLSID
    • 所以我想知道注册表的哪些部分实际上是可选的。

是否有任何"标准"方法来阻止给定注册的 COM 类的 COM 本地服务器可执行文件激活?

我的想法是这个...

只需在检测到服务器以 -Embedding 启动时在 EXE 中设置全局标志即可。 我可能只会在你使用 -Embedding 标志启动时创建一个特殊的类工厂。当调用 IClassFactory::CreateInstance() 时,此类工厂将返回失败代码。 您不会将标准类工厂注册为使用 CoRegisterClassObject() 运行,但只会注册始终返回失败代码的替代工厂。

是的,启动 EXE 时仍然会有轻微的延迟,但是当调用 CreateInstance() 时,它会立即返回失败代码,因此调用方不会有很长的超时时间......也许只有 1-5 秒。

写下到目前为止我从评论中学到的东西:


您不必使用CoCreateInstance,但您可以使用GetActiveObject,这

检索指向已向 OLE 注册的正在运行的对象的指针。

因此,您有一种方法可以在不激活对象的情况下获取对象,而是依赖于它已被注册。(但这不是由CoRegosterClassObject完成的,而是您需要...?


GetActiveObject方法类似,您可以使用IRunningObjectTable周围的机器 - 无论如何,这可能是GetActiveObject在幕后使用的工具。 我有点迷路了。


另一条信息是,注册表声称在所有这些中都是"可选的":(释义)

CoRegisterClassObject只是将对象发布到 COM(作为 oop 服务器), ...

只是不要在注册表中注册对象CLSID。 如果服务器还没有调用CoRegisterClassObject,客户端会得到错误REGDB_E_CLASSNOTREG,否则调用CoRegisterClassObject就足够了。 ...

您不需要将其添加到运行对象表中 - 单个调用CoRegisterClassObject就足够了 - 客户端可以在此之后创建实例。无需在注册表中进行任何注册 - ...

。对于任何远程接口,您当然需要注册表Interface{..}ProxyStubClsid32中的一个条目,但对于CLSID不需要这个条目。

CoRegisterClassObject根本不需要注册表...但是您仍然需要封送您的界面。为此,您需要Interface{..}ProxyStubClsid32密钥。

执行此类封送处理所需的TypeLib- 在此处设置 {00020424-0000-0000-C000-000000000046}。您不需要的CLSIDAppID

CLSID和启动应用所需的APPID(如果未启动)(或加载 DLL)。

如果您已经在运行并呼叫CoRegisterClassObject- 这足以让客户端呼叫连接到您。 但是如果没有CLSID,客户端就无法执行您的应用程序(根本不知道是什么)。

如果您不执行自定义封送处理 - 需要每个接口在注册表中都有信息 - 哪个 dll ProxyStubClsid32 执行此封送处理。这可以是自定义 dll,或者如果标准 {00020424-0000-0000-C000-000000000046},则需要一个 typelib 供 oleaut32 使用。


总之,似乎防止Windows激活应用程序的方法是

  • 首先不要将激活所需的信息写入注册表。
    • 但只有封送处理所需的信息。
  • 和/或不调用CoCreateInstance并通过其他路由检索对象。

最新更新