Sunday, March 22, 2009

Good COM Interop Practices

I'm going to explain good practices you should follow to use a .NET
object from COM. I do want to warn you that all the classes and
interfaces in an Assembly are by default visible to COM. This means
that if you do use an Assembly that does not follow the steps below
there is potential for problems because GUIDs are auto generated by
the .NET runtime based on the signature of the type.

1. To access the attributes you are going to use add the following to
the files you are modifying:


uses System.Runtime.InteropServices;



2. If your assembly is not accessed from COM just add the
ComVisible(False) attribute to be safe. The reason for making all
Assemblies not visible to COM by default is that it is much easier to
hide the entire Assembly and then selectively make individual classes
and interfaces visible. If you register an Assembly with all of its
contents visible then each of those classes and interfaces will
clutter the registry and this isn’t always pretty when you go
to unregister - more on this later. Add the following attributes to
your AssemblyInfo file:


[assembly: ComVisible(False)]
[assembly: GuidAttribute('YourGuid')]
[assembly: TypeLibVersion(X, Y)]


3. To make an object available to COM it must implement an interface, be made visible to COM and implement a default constructor or the CoClass won't have a CanCreate flag.. The interface will become a COM interface and
the object will become a CoClass. On the interface put the following
attributes:


[ComVisible(True)]
[GuidAttribute('YourGuid')]


4. When generating a type library from an Assembly a .NET object creates
two entries in the type library. For example the type library
generated from Assembly Flubber.dll containing object Foo will
contain the CoClass Foo and the default interface for Foo called
_Foo. This is a perfectly valid interface but there are no methods on
it. You can pass it back to .NET and it’ll know what to do with
it. You can even cast it to IDispatch and call Invoke on it but that
isn’t much fun. To not generate the default interface put the
following attributes on the objects you want visible to COM:


[ComVisible(True)]
[GuidAttribute('YourGuid')
[ClassInterface(ClassInterfaceType.None)]


5. If you are using Delphi 2005 you can import the COM object by using
the Import Component Wizard available on the Component menu. This
will display all the Assemblies registered in the GAC and you can
browse to any other Assembly on your system. When clicking the Finish
button the following steps are done for you that users of previous
versions of Delphi will need to follow:


regasm.exe /tlb YourAssembly.dll
tlibimp.exe YourAssembly.dll


It is important to register the type library of an Assembly so you get
type library marshalling. You should only care about this if you use
threads.

6. It is important to unregister your Assembly if you are making
changes. To unregister the assembly with Delphi 2005 you can use
tregsvr.exe:


tregsvr.exe -u YourAssembly.dll


but if you don't have Delphi 2005 or later you will need to type:


regasm.exe /u /tlb YourAssembly.dll

No comments: