Exposing Com Events - C#
With C#'s declerative programming ability it's relatively easy to expose the types to COM environment. But there are a few thing you must pay attention if you want to raise events from your managed COM component. I'll not go into the details of COM programming with C# but just focus on events for now.
Thanks to ComSourceInterfaces attribute; by using this attribute you can easily point to an interface which has the event declerations for your COM type. But before using that attribute you must have an interface to declare your type's events. (Keep in mind events are "dispatched", which means your interface that will contain the event declerations should implement IDispatch)
Here is a sample interface:
[
ComVisible(true)] //Exposed
[
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] //Our managed interface will be IDispatch
public interface IMathEvents {
void OnOperationCompleted(string message);
}
And of course we need a class that will implement that interface and expose our event to COM. Here it is:
[
ClassInterface(ClassInterfaceType.None)]
[
ComSourceInterfaces(typeof(IMathEvents))] //Our event source is IMathEvents interface
public class Math : ServicedComponent , IMath /*IMath interface just declares a method named Add */
{
public int Add(int x, int y) {
if (null != this.OnOperationCompleted)
this.OnOperationCompleted("Operation completed");
return x + y;
}
[
ComVisible(false)]
public delegate void OperationCompletedDel(string message); //No need to expose this delegate
public event OperationCompletedDel OnOperationCompleted;
}
We need the ClassInterface attribute and we need to set it to None. If we dont do that we'll end up with a class and two different interfaces one of which has the method and the other one having the event. And for example if you need to access that class from VB you'll end up with two interfaces which may be confusing such as;
Private WithEvents ? obj as IMath <--- Cannot access events ??
Private WithEvents ? obj as IMathEvents <-- Cannot access the Add method ??
But obviously we need to be able to access both the event and members ;) thanks to ClassInterface attribute. So we can:
Private WithEvents obj as Math
Comments
Anonymous
November 19, 2008
PingBack from http://blog.a-foton.ru/index.php/2008/11/20/exposing-com-events-c/Anonymous
February 17, 2009
this is the closest article I found to solving this problem, but it doesn't work. I assume that you forgot to use [ComVisible(true)] for class Math, but it still throws automation type not supported when compiling VB code.Anonymous
February 20, 2009
Actually, the automation type error was my bug. This solution works for me but I have to set [ComVisible(true)] for all interfaces and the class that implements them. Thanks Murat.Anonymous
February 20, 2009
I didnt have time to fix the code but nice to hear that you have found the solution John.Anonymous
November 18, 2010
So how can you hook up multiple clients that are all able to receive an OperationCompleted event generated from any other client?Anonymous
November 25, 2010
sorry but this doesn't work , period! i created a test app with the code above, namespace COMTest { [ComVisible(true)] //Exposed [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] //Our managed interface will be IDispatch public interface IMathEvents { void OnOperationCompleted(string message); } //And of course we need a class that will implement that interface and expose our event to COM. Here it is: [ClassInterface(ClassInterfaceType.None)] [ComSourceInterfaces(typeof(IMathEvents))] //Our event source is IMathEvents interface [ComVisible(true)] public class Math : ServicedComponent , IMathEvents /*IMath interface just declares a method named Add */ { [ComVisible(true)] public delegate void OperationCompletedDel(string message); //No need to expose this delegate [ComVisible(true)] public event OperationCompletedDel OnOperationCompleted; //void OnOperationCompleted(string message); public int Add(int x, int y) { if (null != this.OnOperationCompleted) this.OnOperationCompleted("Operation completed"); return x + y; } } } why declarating IMathEvents and don't use ? where are the interface "IMath interface just .." ? when i compile, the error is : Error 1 'COMTest.Math' does not implement interface member 'COMTest.IMathEvents.OnOperationCompleted(string)' can you enlight me ?Anonymous
December 21, 2010
It really works! Thanks for the sharing! regards, TerrenAnonymous
December 22, 2010
cealex. As stated on the comments IMath has an Add method only, you could create that interface yourself. And for the IMathEvents interface; it's beng implemented by the Math class but not inherited from it. Check out the ComSourceInterfaces attribute. If you stick with the original code I dont see a reason why it shouldn't work. For more info please take a look at msdn.microsoft.com/.../dd8bf0x3(v=VS.100).aspxAnonymous
December 22, 2010
The comment has been removedAnonymous
June 21, 2013
Good one. As John mentioned, even class has to be made COM Visible.