Registration-Free COM not playing nice with single threaded objects. Activation context dropped during marshaling

236 views Asked by At

I'm working on integrating a COM/CLI based library into a Java based application through JNI (yeah, it's a bit of a mess). For the most part it's working, but I've hit a bit of a snag when it comes to how activation contexts interact with single threaded COM objects. The situation I have can be summed up by the code snippet below.

// 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;
}

The deployment of the library and the application forces me to use Registration-Free COM. Also, since the main application is written in Java I can't really attach a manifest resource to the exe file or anything like that. Hence, I need to use the activation context mechanism in COM to allow the library to look up its COM classes. Also, the library itself is single threaded, so it requires an STA to run in. My application, however, will call the library from all sorts of threads.

From what I understand COM will spin up a new "default STA thread" the first time CoCreateInstance is called from an MTA thread, if the object to be created is single threaded. The actual object is then created in the default STA and the return value of CoCreateInstance will then be a proxy object which marshals method invocations back and forth to the default STA. This is all fine, and is how I want it to work.

My problem appears when my code is not the first one to cause the default STA thread to be started. It seems like even though the object creation is marshaled to the default STA, the current activation context is not. The default STA is stuck with the activation context that was active at the time it was created. What this means for me is that if i'm not the first one to cause the default STA to be initialized my calls to CoCreateInstance will fail, since the default STA doesn't know about my activation context. This is a large enterprisey application, and I can't be sure my code will be the first to call CoCreateInstance, and even if I could this seems like a brittle solution to me.

Thus, I would need one of the following:

  1. A way to marshal the activation context to the default STA.

  2. A way to spin up a new STA with the correct activation context where my objects will live and have CoCreateInstance and method invocations be marshalled back and forth to this STA instead of the default STA.

  3. Refactor my integration to make sure all calls to the problematic library are from a single STA which I have control over, to avoid the marshaling step. This is my backup plan, but I feel there must be an easier way.

0

There are 0 answers