using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; namespace Vanara.InteropServices { /// /// Helper class to create an advised COM sink. When this class is constructed, the source is queried for an /// reference. /// public class ComConnectionPoint : IDisposable { private readonly List<(IConnectionPoint, int)> connectionPoints = new List<(IConnectionPoint, int)>(); /// Initializes a new instance of the class. /// The COM object from which to query the reference. /// The object which implements the COM interface or interfaces signaled by an event. /// The interfaces supported by that support events. public ComConnectionPoint(object source, object sink, params Type[] interfaces) { if (source is null) throw new ArgumentNullException(nameof(source)); if (source is not IConnectionPointContainer connectionPointContainer) throw new ArgumentException("The source object must be COM object that supports the IConnectionPointContainer interface.", nameof(source)); Sink = sink ?? this; if (interfaces == null) interfaces = GetComInterfaces(Sink); if (interfaces.Length < 1) throw new ArgumentOutOfRangeException(nameof(interfaces)); // Start the event sink foreach (var i in interfaces) { var comappEventsInterfaceId = i.GUID; connectionPointContainer.FindConnectionPoint(ref comappEventsInterfaceId, out var connectionPoint); connectionPoint.Advise(Sink, out var cookie); connectionPoints.Add((connectionPoint, cookie)); } } /// Initializes a new instance of the class. /// The COM object from which to query the reference. /// /// The object which implements the COM interface or interfaces signaled by an event. All COM interfaces implemented by this object /// will be used to setup the connection points. If this object implements COM interfaces that cannot be used as connection points, /// use the constructor that allows for supported interfaces to be specified. /// public ComConnectionPoint(object source, object sink) : this(source, sink, null) { } /// Gets the sink. /// The sink. public object Sink { get; private set; } private static Type[] GetComInterfaces(object sink) => sink?.GetType().GetInterfaces(). Where(i => i.GetCustomAttributes(true).Any(a => a.GetType() == typeof(ComImportAttribute) || a.GetType() == typeof(InterfaceTypeAttribute))). ToArray(); /// Releases unmanaged and - optionally - managed resources. public void Dispose() { foreach (var pair in connectionPoints) { //unhook the event sink pair.Item1.Unadvise(pair.Item2); } connectionPoints.Clear(); Sink = null; } } }