'How to get CoCreateInstance to create a new object

I have written an exe (C++, MFC) that exposes an interface for creating a COM object, i.e., my "com server". The COM object has a function that displays a dialog. I now wrote a second exe that creates this COM object and runs the function, i.e., my "com client".

Here is the code in the "com client":

MKS::IApplication*  pMKSApp = nullptr;   // the com object
CLSID id;
HRESULT hr0 = CoInitialize(NULL);
HRESULT hr1 = CLSIDFromProgID(OLESTR("MKS.Application"), &id);
HRESULT hr2 = CoCreateInstance(id, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pMKSApp));
pMKSApp->ShowDialog();   // the function which displays the dialog
// at this point there is only one "com server" exe running
pMKSApp->Release();

When I run the client the functionality works fine - the dialog is displayed and works well. However, if I am running the "com server" exe and then run the "com client" exe (both running at the same time), the dialog is displayed but the "com server" becomes inactive - the dialog is being displayed with the server as its parent. If I check task manager, there is only one instance of the "com server" running. It seems that CoCreateInstance is not creating a new server but reusing the one that is already running.

How, can I get the "com client" to create a new instance of the "com server"? (I am new to com so I apologize if my terminology is incorrect.)



Solution 1:[1]

Simon, thank you for the guidance. As you said, the issue was a "server issue" rather than a "client issue". And, as I dug into the code, I found it was more of a MFC issue.

Within my code, I use MFC's IMPLEMENT_OLECREATE_FLAGS macro which instantiates a COleObjectFactory object which takes care of creating the class factory. Looking at the MFC source code for COleObjectFactory (olefact.cpp) the CoRegisterClassObject function is called:

SCODE sc = ::CoRegisterClassObject(m_clsid, &m_xClassFactory,
    CLSCTX_LOCAL_SERVER,
    m_bMultiInstance ? REGCLS_SINGLEUSE : REGCLS_MULTIPLEUSE,
    &m_dwRegister);

The value of the m_bMultiInstance variable decides which REGCLS value to use. Unfortunately, this value is set from within the IMPLEMENT_OLECREATE_FLAGS macro. Here is the macro definition:

#define IMPLEMENT_OLECREATE_FLAGS(class_name, external_name, nFlags, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    COleObjectFactory class_name::factory(class_name::guid, \
        RUNTIME_CLASS(class_name), FALSE, nFlags, _T(external_name)); \
    AFX_COMDAT const GUID class_name::guid = \
        { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; \

The third argument to the construction is FALSE - this is the value of the m_bMultiInstance variable. So, the solution I came up with was to redefine the macro with the third argument set to TRUE.

/// Redefine macro with argument set to true - create new instance for every client
#undef IMPLEMENT_OLECREATE_FLAGS
#define IMPLEMENT_OLECREATE_FLAGS(class_name, external_name, nFlags, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    COleObjectFactory class_name::factory(class_name::guid, \
        RUNTIME_CLASS(class_name), TRUE, nFlags, _T(external_name)); \
    AFX_COMDAT const GUID class_name::guid = \
        { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; \

It now seems to be working as desired. In task manager I can now see that a new instance of the server application is created when a request is made by the client. Thanks again for the help.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kevin