Search code examples
c#vb6com-interop

VB6/COM Interop: where do these events come from?


I have written a COM-visible class library in C# 4.0 which I'm consuming with VB6. The thing works, only if I open up the VB6 object browser and look at the members exposed, I'm seeing an event for each and every single exposed member... but the C# code doesn't define any of them.

Is this normal? Am I doing something wrong?

[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IMyClass))]
public class MyClass : IMyClass
{
    public void DoSomething(string someParam)
    {
        ...
    }
}

public interface IMyClass
{
    void DoSomething(string someParam);
}

The assembly is signed with a strong name key and AssemblyInfo.cs has the [assembly: ComVisible(true)] attribute set, but I'm not sure it has anything to do with the issue.

When I look at the object browser in VB6, I would be expecting to see DoSomething(string) as a member of MyClass, and I do, however I'm also seeing an event with a matching signature for every exposed method, like Event DoSomething(someParam As String) as a member of MyClass.

Even more puzzling (to me at least), properties also have a "matching" event (can only tell from the little lightning icon though) - if MyClass defined a property like this:

public string SomeProperty { get; set; }

The VB6 object browser would say the "event" is defined as Property SomeProperty As String, which leaves me flabbergasted - how does a "property" 1) gets duplicated and 2) the duplicate gets displayed with an "event" icon in the object browser? The same applies to get-only properties, which have their read-only "property/event" counterpart.

Where do these events come from and how do I get rid of them?

UPDATE An image is worth a thousand words:

COM Interop - bogus events

UPDATE The wrong thing was the ComSourceInterfaces attribute which was mistakenly being used in place of a ComDefaultInterface attribute. Swapping the former for the latter gives the expected result:

COM Interop - correct members


Solution

  • By passing typeof(IMyClass) as an argument to the ComSourceInterface attribute you're saying that everything in the IMyClass is an event.

    If you don't want an event interface for your class remove the ComSourceInterface attribute.

    If you do want to expose events from your C# class to VB then do the following:

    When you create a COM visible class you'll also want to create an interface that defines just the event handlers for your class. Your class should be decorated with the COMSourceInterface specifying your event handler interface and should define your events and implement the event handler interface. See How To: Raise Events Handled by a COM sink for another example.

    [GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967") ]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
    public interface MyEvents
    {
        void ConnectedEvent(string state);
    }
    
    
    [ComSourceInterfaces(typeof(MyEvents))]
    public class MyClass
    {
        public event Action<string> ConnectedEvent;
    
        public MyClass() { }
    
        public void DoSomething(string state)
        { 
            if (ConnectedEvent != null)
                ConnectedEvent(state);
        }
    }
    

    See also: Murat's Corner: Exposing COM Events