Search code examples
winapicom

How to register a COM class in memory?


I have a COM class (e.g., CLSID_WidgetFactory) that I want to make available to anyone in my process who calls:

CoCreateInstance(CLSID_Widget, ...);

But i want to make it available without having to register it, or include it in a registration-free COM assembly manifest.

Core question

I have:

  • a clsid (CLSID_Widget)
  • an IClassFactory implementation

How can i register the these with the COM infrastructure so that anyone in my process can create the COM object?

Obviously I want to accomplish this:

  • without registering the COM object in the HKLM\Software\Classes registry hive
  • without registering the COM object in the HKCU\Software\Classes hive
  • without create a registration-free COM assembly manifest

Conceptually i would have my classID, and my factory object:

class WidgetFactory : ComObject, IClassFactory
{
   //IClassFactory methods
   HRESULT CreateInstance(IUnknown unkOuter, Guid iid, out obj)
   {
      Widget widget = new Widget();

      HRESULT hr = widget.QueryInterface(iid, out obj);
      return hr;
   }
}

Then i want to register my class factory:

Guid CLSID_Widget = "{0677445E-EA9B-447A-AF2E-CCD86E49CED0}";
IClassFactory factory = new WidgetFactory();

RegisterClassFactory(CLSID_Widget, factory);

All that's left is to figure out how to register a COM Class in-memory:

void RegisterClassFactory(Guid clsid, IClassFactory classfactory)
{
   //...
}

Search terms

  • How to register a COM object in memory
  • How to register a COM class in my process
  • How to register a CLSID in memory
  • How to register IClassFactory in my application

Note: I know the answer. But i can't figure out the correct set of search terms that would trigger a hit.

Bonus Reading


Solution

  • You can use CoRegisterClassObject with CLSCTX_INPROC_SERVER and REGCLS_MULTIPLEUSE.

    DWORD RegisterClassFactory(Guid clsid, IClassFactory factory)
    {
       /*
          Register a COM class in-memory. 
          Any requests by COM to create object clsid will use the 
          class factory given by factory.
          This means that a COM object does not have to be registered
          in the registry in order to use it. Nor does it have
          to be included in an application manifest.
    
          Public domain: No attribution required.
       */
       DWORD dwCookie; //returned cookie can be later used to delete the registration
    
       HRESULT hr = CoRegisterClassObject(
             clsid,                // the CLSID to register
             factory,              // the factory that can construct the object
             CLSCTX_INPROC_SERVER, // can only be used inside our process
             REGCLS_MULTIPLEUSE,   // it can be created multiple times
             out dwCookie          // cookie we can later use to delete the registration
       );
       OleCheck(hr);
    
       return dwCookie;
    }
    

    And now anyone in your process can create this arbitrary COM object (even though it isn't registered in the registry, and was not included in an assembly manifest):

    CoCreateInstance(CLSID_Widget, null, CLSCTX_INPROC_SERVER, IID_IUnknown, out unk);
    

    If you're registering several classes, you can combine the REGCLS_SUSPENDED flag (e.g. with the or operator |):

    Suspends registration and activation requests for the specified CLSID until there is a call to CoResumeClassObjects. This is used typically to register the CLSIDs for servers that can register multiple class objects to reduce the overall registration time, and thus the server application startup time, by making a single call to the SCM, no matter how many CLSIDs are registered for the server.

    Note This flag prevents COM activation errors from a possible race condition between an application shutting down and that application attempting to register a COM class.

    and then call CoResumeClassObjects once to register the classes atomically.

    If you intend to perform this from a DLL, you should make sure the DLL provides an entry point for registration at the start of the application. Or just don't use the resume and suspend class objects functions.