I kept promising myself I would write a post on how to expose a .NET
assembly to COM without having to use
RegASM.exe. Someone asked me
today for the very code to do this, so I thought now would be as good
as time as any to write my post.
Microsoft provided a wonderful thing when they invented COM Interop.
Most developers know about calling existing COM components from inside
a C# or VB.NET application, but fewer developers know about operating
the system in reverse - calling .NET from VB6 or C++ via COM.
My code, attached below, emulates exactly what RegASM.exe does, but
provides the developer better control over what happens to the registry
and GAC. To successfully expose a .NET class, contained in an assembly, via COM the following things have to happen:
• Said .NET assembly must be added to the GAC (Global Assembly
Cache). There is debate on whether this is true. However, it's
generally a good idea to install an assembly in a fixed location when
adding registry hooks to that location, and what better place than the
GAC. Non-GAC'd assemblies are liable to break when moved or overwritten
by newer non-backwards compatible versions. The GAC will ensure the
correct version of an assembly is maintained and contained (look, it
even rhymes).
• Registry entries must be added for each exposed class and
interface. Regular COM classes refer to in-proc or out-proc dynamic
link library servers. When exposing a .NET assembly the registry
entries refer to the .NET framework core (mscoree.dll) as the server.
The .NET framework will intercept all COM calls and load the .NET
assembly on behalf of the calling process.
• A type library is to be generated to provide calling applications with a map of exposed interfaces, methods and properties.
The code attached provides all of the above:
Installer.cs - Provides methods to add and remove .NET assemblies to
and from the GAC, and to install and uninstall registry entries.
RegistryValue.cs - Helper class for registry value entries.
TypeLibGen.cs - Helper class for type lib generation.
At the end I have included example code to install and remove
assemblies, as well as what attributes need to be added to a .NE
assembly to make it exportable via COM.
A note on TypeLib generation:
I haven't been able to find some nice C# code to generate type
libraries from .NET assemblies using reflection, so I had to use the
built in TypeLibConverter method - ConvertAssemblyToTypeLib.
Unfortunately this method doesn't allow me to specify what classes,
methods and attributes are exported to the type library, it exports all
public classes and types. This can be confusing - the registry may not
contain registry entries for some of these exported types, depending on
how you attribute your code.
To avoid this problem, attribute all public classes and types with
[ComVisible(False)] if not intended to be callable from COM. I show
this in my example at the bottom of the code.
Download code here.