tags:

views:

67

answers:

3

I have a legacy C++ "solution engine" that I have already wrapped as an in-process COM object for use by client applications that only require a single "solution engine".

However I now have a client application that requires multiple "solution engines". Unfortunately the underlying legacy code has enough global data, singletons and threading horrors that given available resources it isn't possible to have multiple instances of it in-process simultaneously.

What I am hoping is that some kind soul can tell me of some COM magic where with the flip of a couple of registry settings it is possible to have a separate out-of-process COM server (separate operating system process) for each instance of the COM object requested.

Am I in luck?

A: 

I'm pretty sure this is not possible. A COM out-of-proc server has to globally register the class objects it provides (via CoRegisterClassObject); part of this registration is the class GUID. Obviously you cannot register the same GUID twice.

Luke
-1: It is possible. See my post.
John Dibling
You learn something new every day.
Luke
+1  A: 

You would need a "master" coclass to lock in the EXE instance, similar to an "Application" interface. Locate the CoRegisterClassObject() call for its factory. And change the REGCLS argument to REGCLS_SINGLEUSE.

This will automatically unregister the class factory as soon as the first client connects to it. Calling CoCreateInstance() for that factory again starts a new instance of the server. I think.

Hans Passant
+2  A: 

Yes, this is possible. The key is to register your coclass by calling CoRegisterClassObject, and OR-in the value REGCLS_SINGLEUSE in the flags parameter.

If your project is an ATL 7.0+ project, you can do this by overriding CAtlExeModuleT::PreMessageLoop(), which is responsible for registering the class object, thusly:

HRESULT CATLHacksModule::PreMessageLoop(int nShow)
{
    HRESULT hr = RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE);
    if (hr == S_OK)
    {
        if (m_bDelayShutdown && !StartMonitor())
        {
            hr = E_FAIL;
        }
    }
    else
    {
        m_bDelayShutdown = false;
    }
    return hr;
}
John Dibling
Before I start implementing this I just want to resolve any ambiguity. I need a solution where a single "client.exe" process using multiple instances of "mycomobject" will result in multiple instances of a "mycomobject.exe" process being started.
Tom Williams
@Tom: Yes, that's exactly what this will do. If you want to demo this to yourself (and I suggest you do before deploying this to production code), make a little COM server without the above code, and test it against a client. Give your COM object a property that returns `GetCurrentProcessId`. You will find if you `CoCreateInstance` your interface 5 times without `REGCLS_SINGLEUSE` it will use a single process, but if you write the code above there will be 5. This is what I did to answer your question.
John Dibling
Thanks, I'll be sure to upvote once I've tried that out.
Tom Williams
Works great. Thank you.
Tom Williams