Wednesday, August 06, 2008
Creating C# DLL's for use with COM is not too hard, however event exposure can be a little messy especially when trying to subscribe to events in vb6 or vba.
Here's an example of an everyday COM exposed class:
ComVisible(true)
ClassInterface(ClassInterfaceType.AutoDual)
public class CComInterop
We've integrated automatic interface generation so we don't have to make our own. However, this interface type does not expose events.
The solution is to create a separate interface to expose the events but no other properties / methods of the class. Using some jiggery pokery it is also possible to integrate the contents of this interface into the class itself so that you don't have to deal with multiple objects on the COM side.
METHOD:
this is our event, and the event's delegate:
public event SomeEventHandler SomeEvent;
public delegate void SomeEventHandler(string teststring);
To expose this event we create the following interface:
ComVisible(true)
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)
public interface IComInteropEvents
{
void SomeEvent(string teststring);
}
The important part is that we specify the interface type as IDispatch.
But we don't want to have to declare a separate object for events, so we add a 'ComSourceInterfacesAttribute' referencing this interface, like so:
ComVisible(true)
ComSourceInterfacesAttribute("Tam.Common.LzLibrary.IComInteropEvents")
ClassInterface(ClassInterfaceType.AutoDual)
public class CComInterop
Now we can use the object's events in vb6 or vba without having to declare separate objects!
Public WithEvents InteropObject As Some_Library.CComInterop
and you can still use the methods and properties of the object normally with all intellisense intact.
Full sample Class and interface shown below:
ComVisible(true)
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)
public interface IComInteropEvents
{
void SomeEvent(string teststring);
}
public delegate void SomeEventHandler(string teststring);
ComVisible(true)
ComSourceInterfacesAttribute("Tam.Common.LzLibrary.IComInteropEvents")
ClassInterface(ClassInterfaceType.AutoDual)
public class CComInterop
{
private int m_nSomeProperty = 0;
public event SomeEventHandler SomeEvent;
public void SomeMethod(int nValue)
{
m_nSomeProperty = nValue;
// Raises the event
SomeEvent("Hello");
}
public int SomeProperty
{
get { return m_nSomeProperty; }
set { m_nSomeProperty = value; }
}
}
Enjoy!