我正致力于通过JNI将基于COM / CLI的库集成到基于Java的应用程序中(是的,它有点混乱)。在大多数情况下它都在工作,但是当谈到激活上下文如何与单线程COM对象交互时,我遇到了一些障碍。我所拥有的情况可以通过下面的代码片段来总结。
// This function, workGlue, will be called from an MTA thread.
int workGlue(int foo)
{
ULONG_PTR cookie;
ActivateActCtx(myActivationContext, &cookie);
// The doWork function is part of an external library.
// Internally it will call CoCreateInstance to create
// a single threaded COM object which needs to be looked up
// in the activation context.
int result = doWork(foo);
DeactivateActCtx(0, cookie);
return result;
}
库和应用程序的部署迫使我使用免注册COM。此外,由于主应用程序是用Java编写的,因此我无法将清单资源附加到exe文件或类似的东西。因此,我需要在COM中使用激活上下文机制来允许库查找其COM类。此外,库本身是单线程的,因此它需要STA运行。但是,我的应用程序将从各种线程调用库。
根据我的理解,COM将启动一个新的"默认STA线程"第一次从MTA线程调用CoCreateInstance,如果要创建的对象是单线程的。然后在默认STA中创建实际对象,然后CoCreateInstance的返回值将是一个代理对象,它将方法调用来回调整到默认STA。这很好,我希望它能起作用。
当我的代码不是第一个导致默认STA线程启动的代码时,我的问题出现了。即使对象创建被封送到默认STA,似乎当前的激活上下文也不是。默认STA停留在创建时激活的激活上下文。这对我来说意味着如果我不是第一个导致默认STA初始化的人,我对CoCreateInstance的调用将失败,因为默认STA不知道我的激活上下文。这是一个大型的企业级应用程序,我无法确定我的代码是第一个调用CoCreateInstance的代码,即使我能够这对我来说似乎是一个脆弱的解决方案。
因此,我需要以下其中一项:
将激活上下文编组到默认STA的方法。
一种使用正确的激活上下文来启动新STA的方法,其中我的对象将存在并且CoCreateInstance和方法调用将来回编组到此STA而不是默认STA。
重构我的集成以确保对有问题的库的所有调用都来自我控制的单个STA,以避免编组步骤。这是我的备份计划,但我觉得必须有一个更简单的方法。