Creating early bindable COM objects in .NET 2
Many will ask why do such a daft thing as creating COM objects in .NET? Well the answer is fairly simple, at my current place of work we only have Microsoft Visual Studio 2005 and I needed to create a COM object for compatibility with an older application, which only understood early bound COM. The application is a ‘drag and drop’ business rules and workflow editor, COM can be used to provide additional custom functions otherwise not available.
I thought to myself, this can’t be that difficult, just follow the tickboxes…..
- Project Properties->Application->Assembly Information->Make Assembly COM Visible – Check
- Project Properties->Build->Register for COM Interop (automatically exports a typelibrary) – Check
- Project Properties->Signing-> Sign the assembly (make a new strong key name file) – Check
…. surely that’s enough? Wrong. The assembly was a late bound COM object only.
A few help topics and Googles later, I’m doing all sorts of tricks, adding and deleting things in the GAC and learning the wonders of regasm. However, none of it worked.
Back to basics, the type library defines the interfaces for early binding, so why couldn’t COM see the type library definitions? The answer turned out to be very simple, the C# complier didn’t add the required information into the registry during the build. Help was at hand however, in the form of the attributes [ComRegisterFunction] and [ComUnregisterFunction]. It should be noted that the C# build does add partial information to the registry, but not the required TypeLib key……
[ComVisible(false)]
public class COMBase
{
[ComRegisterFunction]
static void ComRegister(Type t)
{
string keyName = @"CLSID\" + t.GUID.ToString("B");
using (RegistryKey key =
Registry.ClassesRoot.OpenSubKey(keyName, true))
{
using (RegistryKey subkey =
key.CreateSubKey("TypeLib"))
{
Guid libid =
Marshal.GetTypeLibGuidForAssembly(t.Assembly);
subkey.SetValue("", libid.ToString("B"));
}
using (RegistryKey subkey =
key.CreateSubKey("Version"))
{
Version ver = t.Assembly.GetName().Version;
string version =
string.Format("{0}.{1}", ver.Major, ver.Minor);
subkey.SetValue("", version);
}
}
}
[ComUnregisterFunction]
static void ComUnregister(Type t)
{
string keyName = @"CLSID\" + t.GUID.ToString("B");
Registry.ClassesRoot.DeleteSubKeyTree(keyName);
}
}
Volia, derive all my ‘COM’ classes from ‘COMBase’ and I have a working early binable COM object. Should also mention, none of the GAC and regasm manual processing is needed either. Not particulary neat, I would certainly like to know if there’s a better way.
As an aside, during my time with COM in .NET I picked up a few pointers on ‘best practices’ the most useful of which is using defined interfaces, with fixed GUIDs to keep the resultant COM ‘backwards compatible’.
For example:-
[Guid("89B65A92-5CE6-4295-A6DF-9506530C7877")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IFoo
{
int Bar();
}
[ProgId("MyCOMObject.Foo")]
[ClassInterface(ClassInterfaceType.None)]
public class Foo : COMBase, IFoo
{
public int Bar()
{
return 42;
}
}
Should also be noted that explicitly specifiying the COM ‘ProgID’ makes it easier to manage also (and elminates the need to shorten namespaces and class names for COM). Specifiying ‘ClassInterfaceType.None’ for the class effectively hides it from COM, leaving only the parts you want to explicitly expose in the interface.

February 25th, 2007 at 1:54 pm
[...] recently wrote about creating early bound COM objects in .NET, the object (no pun intended) of the exercise was to persuade Visual Studio 2005 to produce an [...]