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{...}
加上子项ProgID
、VersionIndependentProgID
、LocalServer32
、Typelib
- 客户端当前从 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}。您不需要的CLSID
和AppID
。
CLSID
和启动应用所需的APPID
(如果未启动)(或加载 DLL)。如果您已经在运行并呼叫
CoRegisterClassObject
- 这足以让客户端呼叫连接到您。 但是如果没有CLSID,客户端就无法执行您的应用程序(根本不知道是什么)。如果您不执行自定义封送处理 - 需要每个接口在注册表中都有信息 - 哪个 dll ProxyStubClsid32 执行此封送处理。这可以是自定义 dll,或者如果标准 {00020424-0000-0000-C000-000000000046},则需要一个 typelib 供 oleaut32 使用。
总之,似乎防止Windows激活应用程序的方法是
- 首先不要将激活所需的信息写入注册表。
- 但只有封送处理所需的信息。
- 和/或不调用
CoCreateInstance
并通过其他路由检索对象。