Minimal COM object registration

Yesterday I mentioned the APPID registry key.  I also mentioned the effort going on within Microsoft to reduce redundant COM related registry keys.

We use about a dozen COM objects internally within the audio subsystem of Vista, and after talking to the COM guys about what we REALLY need to specify, we’ve settled on the following for registration of the objects.  I believe it’s the minimal set of registry values you need to have a fully functional COM object:

    Default Value: “Friendly Name for the class”         not actually required, but useful for tools like oleview and dcomcnfg
Key: HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocServer32\”
    Default Value: REG_EXPAND_SZ: <DLL Name>
    Value “ThreadingModel” REG_SZ “both”

That’s it – two keys and a single non default value.

Of course, by specifying such a restricted set of keys, you lose a lot of functionality.  For instance, since there’s no PROGID specified, you can’t call CLSIDFromProgID or activate the object via name (such as using the szProgID version of the CComPtrBase<>::CoCreateInstance method).  In addition, without additional information, you can’t marshal the object cross process.  It’s also not accessible from script, or from the CLR (because there’s no typelib registered).  And finally, while the object is marked with a threading model of “both”, it can’t be used from the STA unless the COM object aggregates the FreeThreadedMarshaller.

But if all you need is to be able to have an application activate your COM object in-proc, this is all you need.

Next: What do you need to add if you need your object to work cross-process?

Edit: Added note about aggregating the free threaded marshaller.

Comments (14)

  1. PatriotB says:

    "after talking to the COM guys"

    Oooh, there’s still COM guys at Microsoft? That’s good to hear! All this .NET stuff, sometimes you wonder… 🙂

  2. In this case the guy was from the COSD engineering excellence center, but yes, there are COM guys still around.

  3. mirobin says:

    If I recall correctly, I believe you need to add typelib key under the <clsid> node, typelib registration data, and proxy stub interface registration data.

    Or, more explicitely:

    Key: HKCRClasses<clsid>TypeLib

    Default: TypeLib GUID associated with the class

    Key: HKCRClasses<clsid>Version

    Default: version of class (and associated typelib)

    Key: HKCRTypeLib<typelibid><version><locale>win32

    Default: path to file holding typelib data

    <TypeLibid> = typelib guid

    <version> = version of typelib (and associated classes)

    <locale> = hex lcid (not 100% certain on this one)

    Key: HKCRInterface<ifaceid>ProxyStubClsid

    Default: proxy stub class

    Key: HKCRInterfaces<ifaceid>Typelib

    Version – typelib version

    It may be possible to omit some of these values … there might be reasonable assumptions made if version information is omitted, and it might be possible to leave out some of the typelib references. But I’m not going to experiment to find out; I’ll just wait for your next article instead. 😉

  4. mirobin, no you don’t need all that goop. All you need are the two keys I listed above.

    For the case of a simple in-proc COM object, this is all you need.

    That’s the whole point of this mini-series – to show the minimum amount of registry stuff you need to support COM registration.

    There’s way too many components that put too much crap in the registry when they don’t need it.

  5. Mattias says:

    "It’s also not accessible from script, or from the CLR (because there’s no typelib registered)."

    You don’t need a registered typelib to use COM objects from the CLR. All you nend is a managed representation of the COM interfaces. Tlbimp creates that from a typelib, but you can just as well write them manually by translating the IDL for example.

  6. mattias, yes, but if you want interop to work automatically, you need the typelib.

  7. mirobin says:

    Larry, my post was intended to answer "What do you need to add if you need your object to work cross-process?"

  8. mirobin, sorry, I didn’t realize that.

  9. mirobin says:

    No worries; in retrospect, I didn’t make it particularly clear either. 🙂

  10. MT says:

    >… marked with a threading model of "both",

    > it can’t be used from the STA unless

    This is wrong. When martk at Both you do not need to implement IMarshall when creating object from an STA. You woulkd need to do this if the object was marked as Free.



  11. MT, that’s true for some cases, but not in general. You need to implement IMarshall whenever you attempt to do anything with the object that COM thinks would involve marshalling. That includes accessing the object from another thread.

    If you’re lucky, you’ll get away with it, but it’s been my experience that for any but the simplest BOTH threading model COM objects, you’re going to get burned really quickly.

    Aggregating the FTM is trivial to do and it saves a huge amount of grief down the line.

  12. MT says:

    >Aggregating the FTM is trivial to do

    >and it saves a huge amount of grief down

    >the line

    It can also cause a *lot* of problems if your object holds a reference to other COM objects.

    See Don Box, Essential Com, Item 33 – Beware the Free-Threaded Marshaler (FTM).


  13. MT, I’ll check with Don, but afaik, the only time you’ll have problems aggregating the FTM is if you’re playing apartment games with your referenced COM objects. In other words, if you ensure that every referenced COM object matches your threading model you should be fine.

    If the threading model doesn’t match, then you should put the COM object in the GIT, which will correctly handle marshalling that object for you.

    This is a general purpose rule, IMHO – if the object you’re referencing doesn’t match your object’s threading model (and by definition, COM objects with a threading model of "both" don’t match your objects threading model (since objects with a threading model of "both" take on the threading model of the thread that created them)), then you need to put the object in the GIT.