COM Development C#

COM Development C#

COM (Component Object Model):

COM is a platform-independent, distributed, object-oriented system for creating binary software components that can interact. COM is the foundation technology for Microsoft’s OLE (compound documents) and ActiveX (Internet-enabled components) technologies.

C# provides programming mechanisms that simplify the implementation of COM objects. These objects can be within a single process, in other processes, even on remote computers.

C# objects to COM requires declaring a class interface, an events interface if it is required, and the class itself. Class members must follow these rules to be visible to COM:

  • The class must be public.
  • Properties, methods, and events must be public.
  • Properties and methods must be declared on the class interface.
  • Events must be declared in the event interface.

Other public members in the class that are not declared in these interfaces will not be visible to COM, but they will be visible to other .NET Framework objects.

To expose properties and methods to COM, you must declare them on the class interface and mark them with a DispId attribute, and implement them in the class. The order in which the members are declared in the interface is the order used for the COM table.

To expose events from your class, you must declare them on the events interface and mark them with a DispId attribute. The class should not implement this interface.

The class implements the class interface; it can implement more than one interface, but the first implementation will be the default class interface. Implement the methods and properties exposed to COM here. They must be marked public and must match the declarations in the class interface. Also, declare the events raised by the class here. They must be marked public and must match the declarations in the events interface.

using System.Runtime.InteropServices;

namespace project_namespace
{
    [Guid("FAA4976A-45C3-4BC5-BC0B-E474F4C3C83S")]
    public interface ComClassInterface
    {
    }

    [Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"), 
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ComClassEvents 
    {
    }

    [Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
        ClassInterface(ClassInterfaceType.None),
        ComSourceInterfaces(typeof(ComClassEvents))]
    public class ComClass : ComClassInterface
    {
    }
}

Note: IntropService class object having the power to make your COM existence hence must be declared under using reference section.

Building the Class: Create a basic class with a constructor and simple method that returns a value of int type:

public class MyComExample
{
	 // constructor - does nothing in this example
	 public MyComExample() {}

	 // a method that returns an int
	 public int AddTwoValues(int oValue1, int oValue2)
	 {
		return oValue1 + oValue2;
	 }
}

Create an Interface:

Note that even though the eventual objective of this exercise is to expose the DLL to the world of COM, the code we are writing is still managed and there needs to be a way to tell the COM clients how to access the public methods/properties of your class. You will also need to determine how you want your COM objects to be called – at compile-time or run-time (i.e. early binding or late binding). Script languages such as Javascript/VB Script/VBA are not compiled and thus have no way of determining the type of COM object it’s calling (in other words, they only support late-binding). Therefore, it’s a lot safer to enable an interface for late-binding than early binding (you can also enable both) unless you have a really good reason to exclude late-binding.

Create a public interface and add an abstract definition of every method or property you wish to expose from your class object in the interface. You can optionally add the attribute [DispId] to each method to manually control how COM services will call them.

public interface IComClassExample
{
	 [DispId(1)]
	 int AddTwoValues(int oValue1, int oValue2);
}

Building Connection:

Firstly, we need to let our class know which interface will be responsible for exposing its methods (you can have multiple interfaces and classes in your namespace if you want, but we will stick with 1 in this example for simplicity’s sake). You can achieve this by derivation, which in this case is to implement the interface. Since we manually created the interface, we need to tell the compiler not to generate another automatically as this will cause confusion. We can do this by using the ClassInterface attribute and setting its value to ClassInterfaceType.None. The code for your class will now look like this:

[ClassInterface(ClassInterfaceType.None)]
public class MyComExample : IComClassExample
{
	// constructor - does nothing in this example
	public MyComExample() { }

	// a method that returns an int
	public int AddTwoValues(int oValue1, int ovalue2)
	{
		return oValue1 + ovalue2;
	}
}

Let’s go Back to our interface, by default, an interface is enabled for both early and late-binding, however in this case we want it to be set to late-binding only. We can use the InterafaceType attribute to achieve this. Note that the InterfaceIsDispatch type corresponds to late-binding.

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IComClassExample 
{
	[DispId(1)]
	int AddTwoValues(int oValue1, int ovalue2)
}

GUID to make COM unique:

Every COM assembly and its public types (i.e. interfaces, classes) need a unique GUID. By default, Visual C# assigns a unique GUID to the entire assembly automatically at compile-time, but it does not do so for the public types. You have two options here. You can either manually generate GUIDs with the guidgen.exe tool and assign them to each type individually or you can use regasm.exe to automatically generate them for you. In this case, we are going to proceed with the former approach.

Start up guidgen.exe and pick Registry format. Generate a new GUID for each of your public types (in the case of this example, one class plus one interface) and paste it into the Guid attribute. Your code should now resemble something like this, note that I moved the square brackets to accommodate more attributes and a comma is used to separate them:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace MyComExample
{
	[Guid("7069AC34-DBB0-4e40-84A7-C2243355E2D7"),
	InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
	public interface IComClassExample
	{
		[DispId(1)]
		int AddTwoValues(int oValue1, int ovalue2)
	}

	[Guid("864FEADA-EE73-4f4a-ABC0-3FB384CB41AA"),
	ClassInterface(ClassInterfaceType.None)]
	public class MyComExample : IComClassExample
	{
		// constructor - does nothing in this example
		public MyComExample() { }

	// a method that returns an int
	public AddTwoValues(int oValue1, int ovalue2)
	{
		return oValue1 + oValue2;
	}
	}
}

Calling an Existing COM: If the library is already registered, you can perform the following steps to have Visual Studio generate an interop assembly for you:

  • Open to your Visual Studio project.
  • Right click on ‘References’ (right under the project in your Solution Explorer) and select ‘Add Reference’.
  • Select the COM tab.
  • Select the Component you wish to interop with.
  • Select OK.
COM img

This will be a class or set of C# classes that wrap all of the COM interface stuff with a normal C# class. Then you just use it like any other C# library. If the import of the reference worked well, you can explore it like any other reference and the methods/structs/classes/constants should show up in that namespace and intellisense.

Next>>Excel Events using C# DOT NET

Leave a Reply

Your email address will not be published.