A while ago, I had the following problem:
- The build system needed to run a unit test of some code that depended on some COM object.
- That COM object was not installed on the build system (it wasn't a part of the system we were developing).
- Installing that COM object would mean having to install a large system with all kinds of dependencies — not exactly something I wanted to do on the build machine...
Fortunately, the interaction with the particular COM object was very basic. I made a fake implementation of it, just returning hard-coded responses for the few calls I needed. With the fake COM object in place, the unit tests passed.
I added some logic to the build file that checks whether a particular ProgID existed in the registry. If not, the build script registers the fake object, runs the specific tests, and then unregisters it again.
If the ProgID is found in the registry, however, just the tests are executed. This allows the build to be also run on a developer's machine containing the back-end system (and not mess up its COM registration). Works great.
Fast-forward to yesterday.
Triggered by a discussion with a co-worker about the fact that the unit tests aren't nicely isolated from the back-end system this way, I suddenly remembered reading about registration-free COM on Junfeng Zhang's blog.
Registration-free COM
As the name implies, registration-free COM makes it possible to use COM objects without registering them. An application gets all activation information (typelib, ProgID-to-CLSID mapping, threading model and the like) from a manifest file, instead of reading it from the registry. This allows multiple applications to use different versions of a COM object, with the same ProgID and/or CLSID.
That's a much nicer solution for my original problem — I no longer have to dynamically register and unregister my fake implementation, and I can use the fake implementation on systems containing the real one as well.
A sample manifest file
The manifest file I'm using looks like this:
<?xml version='1.0' encoding='utf-8'?>
<assembly manifestVersion='1.0' xmlns='urn:schemas-microsoft-com:asm.v1'>
<assemblyIdentity type='win32' name='RegFreeCOM-sample.exe' version='1.0.0.0' />
<file name='FakeTCMXML.dll'>
<comClass clsid='{69c2082a-61b1-4a83-a947-88420fac54fa}'
threadingModel='Apartment'
progid='TCMXML.XMLResponder' />
</file>
</assembly>
I've saved this as RegistrationFreeCOM.exe.manifest
in the same directory as my test application RegistrationFreeCOM.exe
, and also copied my fake implementation FakeTCMXML.dll
into that directory. The test application will activate TCMXML.XMLResponder
from FakeTCMXML.dll
, regardless of whether that ProgID already occurs in the registry, and without affecting that registration.
Creating a manifest file
For many scenarios, the sample manifest file is sufficient: just update the 'name', 'clsid' and 'progid' attributes. You can find the value for 'clsid' in the IDL for your component, or by using OleView.
You can also have Visual Studio 2005 create a manifest file for you: create a throw-away project, reference your COM dll, view the properties of that reference, and toggle the 'Isolated' flag to 'True'. When you build the project, the manifest file will be generated.