Danra
Danra

Reputation: 9916

Are there any 'gotchas' when implementing a COM interface in a .NET class?

It is Known that .NET assemblies/classes can be made COM Visible, so that classes in the assembly can be instantiated as COM objects by COM aware clients.

Are there any 'gotchas' to be aware of?

Upvotes: 2

Views: 122

Answers (2)

Dan Busha
Dan Busha

Reputation: 3803

A couple that I've run into:

  1. COM does not support generics so all of your collections that are accessed via COM will need to be untyped.
  2. While COM support interface inheritance the .Net implementation does not. Since COM is only concerned with interfaces you can use inheritance in your classes, but your interfaces must contain both derived and base class members.

Upvotes: 1

Danra
Danra

Reputation: 9916

Why yes, yes there are.

1) A specific case where this sort of Interop is required is when your class is expected to implement an already existing COM interface. For example, SharePoint offers some plugin architectures where the plugin is registered as a COM class which implements some custom interface.

If you don't have a Primary Interop Assembly for the interface, you supposedly need to add a reference to the TLB or to the DLL containing the TLB. The reference can be added in Visual Studio by selecting "Browse" when adding a reference. If you don't have a TLB you should have an IDL which you can compile into a TLB using midl.exe. Some documentation suggests equivalently to run tlbimp.exe on the TLB and add a reference to the generated assembly.

However...

  • In all likelihood, if you try using the above method, clients will successfully create a COM object instance of your class, but will crash when they call any method on it. This is because the above method messes up the order of the methods in the interface. So the client tries to call method A which expects some parameters, but the entry in the virtual table (assuming the client is C++) actually calls method B!... and tries to marshal the invalid parameters across to its managed implementation.
  • Sometimes the translated parameter types aren't correct (for example, a byte* might be translated to a ref byte).
  • Some interfaces are just translated wrong (Specifically the translated ILockBytes contains the RemoteReadAt and RemoteWriteAt methods, instead of ReadAt and WriteAt).

So, while you can use the assembly auto-generated from the TLB as a starting point - You must fix all the above, either by modifying the assembly or just copying the generated code into source files and then make the required changes.

2) Add a ClassInterfaceAttribute with ClassInterfaceType.None as the type, as recommended in the documentation.

3) Build the assembly for the Any CPU architecture, and then on any machine where you want to register it -

  • If you want to register your assembly for COM consumption by 32-bit processes, register it using C:\Windows\Microsoft .NET\Framework\<version>\regasm.exe.
  • If you want to register your assembly for COM consumption by 64-bit processes, register it using C:\Windows\Microsoft .NET\Framework64\<version>\regasm.exe.

4) Just running regasm.exe doesn't add the .NET assembly to the GAC, so be sure to use the /codebase parameter for regasm.exe if you don't install the assembly in the GAC yourself.

5) Even if Visual Studio runs with Administrator privileges, the assembly's registration will often fail if you check the "Register for COM Interop" checkbox in the build options. It's best to clear the checkbox and instead add regasm.exe as a post build event.

Upvotes: 3

Related Questions