我有一个应用程序使用进程外 COM 服务器访问由进程内 COM 服务器创建的 COM 对象。这意味着进程外的 COM 服务器必须加载进程内的 COM DLL 以创建它随后返回的最终对象。
例如:
// Create an object which resides in the out of process COM server
container.CoCreateInstance("HelperServerProcess");
// Grab a reference to an object which resides in an in process COM server DLL,
// hosted by the out of process COM server
object = container.GenerateResults();
// Release the object instantiated by the out of process server
container = NULL; // or return, or go out of scope, etc
// This call will fail, because the out of process server has shutdown unloading
// the inproc DLL hosting <object>
object.DoStuff();
但是,一旦容器对象被释放,最终的服务器进程引用(在 CoReleaseServerProcess 中)被释放,服务器关闭。这会在尝试使用结果对象时导致 E_RPC_SERVER_UNAVAILABLE 错误。同时,此 EXE 服务器中托管的进程内 DLL 仍有未完成的对象,因此从 CanUnloadNow 返回 S_FALSE。
我认为将 IExternalConnection 添加到 EXE 服务器的类工厂以手动对远程引用进行引用计数不会有帮助,因为 DLL 进程内服务器注册的对象将使用 DLLs 类工厂并尝试在上使用 IExternalConnection这个工厂。此外,如果服务器在其进程空间中生成交互式子对象,则它不会以任何一种方式触发 IExternalConnection。
也无法修改 DLL 的引用计数以使用 CoAddRefServerProcess/CoReleaseServerProcess,因为 DLL 无法访问容器的关闭代码以防它触发最后一个版本,并且无法更改第三方 DLL无论如何。
我能想到的唯一可行的方法是在服务器引用计数为零后添加一个循环,它调用 CoFreeUnusedLibraries,然后以某种方式枚举所有加载的 COM DLL 并等待直到没有加载并确保服务器引用计数仍然存在零。如果加载的 DLL 未正确实现 CanUnloadNow,这将导致进程泄漏,并且涉及弄乱我想避免的低级 COM 实现细节。
有没有更简单的方法来确保进程内服务器的类工厂实例化的COM对象保持进程存活,或者枚举加载到当前进程的DLL的类工厂并查询它们的引用数?
更新:另一种可能有效的方法,但听起来很像你不应该做的事情:拦截进程中的每个衍生线程,通过 CoRegisterInitializeSpy 注册一个 CoInitialize Hook ,并为每个添加服务器进程引用当前已初始化 COM 的线程。
最佳答案
进程外 EXE 可以委托(delegate) DLL 对象而不是直接返回它。让 GetResults()
返回 EXE 实现的对象,并让该实现根据需要在内部使用 DLL。这样,在调用者释放 EXE 的对象之前,EXE 不会被释放,从而保持 EXE 自己的引用计数处于事件状态。 EXE 的对象可以实现 DLL 对象实现的相同接口(interface)。这样,调用者就不知道(或不关心)正在使用委托(delegate)。
关于winapi - 在加载进程内服务器对象实例时防止进程外服务器关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24289794/