我有一个应用程序,它使用进程外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进程内服务器注册的对象将使用DLL类工厂并尝试使用IExternalConnection这家工厂。此外,如果服务器在其进程空间中生成交互式子对象,则不会以任何方式触发IExternalConnection。
也无法修改DLL的引用计数以使用CoAddRefServerProcess / CoReleaseServerProcess,因为DLL无法访问容器的关闭代码,以防它触发上一版本,并且第三方DLL无法更改无论如何。
我能想到的唯一方法是在服务器refcount命中零后添加一个循环,调用CoFreeUnusedLibraries,然后以某种方式枚举所有加载的COM DLL并等待,直到没有加载并确保服务器引用计数仍然是零。如果加载的DLL没有正确实现CanUnloadNow,这会泄漏进程,并且涉及到我希望避免的低级别COM实现细节。
有没有更简单的方法来确保由进程内服务器的类工厂实例化的COM对象使进程保持活动状态,或者枚举加载到当前进程中的DLL的类工厂并查询它们的引用数量?
更新:另一种可行的方法,但听起来非常类似于你不应该做的事情:拦截进程中的每个衍生线程,通过CoRegisterInitializeSpy注册CoInitialize挂钩,并为每个添加服务器进程引用当前已初始化COM的线程。
答案 0 :(得分:2)
out-of-proc EXE可以委派DLL对象而不是直接返回它。让GetResults()
返回EXE实现的对象,并让该实现在内部根据需要使用DLL。这样,在调用者释放EXE的对象之前不会释放EXE,从而使EXE自己的引用计数保持活动状态。 EXE的对象可以实现DLL对象实现的相同接口。这样,调用者不知道(或关心)正在使用委托。