Bagikan melalui


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, Terren

  • Anonymous
    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).aspx

  • Anonymous
    December 22, 2010
    The comment has been removed

  • Anonymous
    June 21, 2013
    Good one. As John mentioned, even class has to be made COM Visible.