Exposing events from .NET to COM

2020-07-30 10:26发布

问题:

recently I have been encountering problems with exposing events from .NET to COM.

I have been successful with this example (conceptually taken from http://blogs.msdn.com/andreww/archive/2008/10/13/exposing-events-from-managed-add-in-objects.aspx):

// The delegate type for our custom event.

[ComVisible(false)]
public delegate void SomeEventHandler(object sender, EventArgs e);

// Outgoing (source/event) interface.
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IAddInEvents
{
    [DispId(1)]
    void SomeEvent(object sender, EventArgs e);
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IAddInEvents))]
public class AddInUtilities :
{       
    // Event field. This is what a COM client will hook up
    // their sink to.
    public event SomeEventHandler SomeEvent;

    inernal void FireEvent(object sender, EventArgs e)
    {
        if (SomeEvent != null)
        {
            SomeEvent(sender, e);
        }
    }
}

This works fine, because the IAddInEvents interface is defined as IDispatch. However, I need to publish an event source interface which is IUnknown. I do not have control over the event interface as it comes from a third-party library (which will also be the consumer of the published events). Whenever I try to hook to the events, VB environment (where I am trying to sink the events) crashes, so does the VBA environment which the third-party product (ESRI ArcMap) uses.

I have been able to (partially) implement IConnectionPointContainer interface (which COM uses in the background to handle events) manually, then I am able to sink the event and step into my IConnectionPointContainer implementation. However, this seems like an overkill to me and I think that there must an implicit support for this in .NET. Second, with this approach I instantly lose the delegate support.

Does anyone have any experience with this? Thanks in advance.

回答1:

Quite simply, you won't be able to do this. Classic VB does not support non-Automation COM (as you have seen).

You will have to have a wrapper that you can pass your Automation instance to which will public the non-Automation event. You are effectively going to have to have two separate types to handle the two separate clients for the events (Automation-enabled and non-Automation enabled).



回答2:

Ok, so I have been able to this by implementing the classic COM IConnectionPointCointainer, IConnectionPoint and IConnection (plus the enumeration interfaces). It does not integrate into the .NET delegate/event model, but works.