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 List> connectionPoints = new List>(); /// 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 == null) throw new ArgumentNullException(nameof(source)); if (sink == null) sink = this; if (interfaces == null) interfaces = GetComInterfaces(sink); if (interfaces.Length < 1) throw new ArgumentOutOfRangeException(nameof(interfaces)); // Start the event sink if (!(source is IConnectionPointContainer connectionPointContainer)) throw new InvalidOperationException("The source object must be COM object that supports the IConnectionPointContainer interface."); foreach (var i in interfaces) { var comappEventsInterfaceId = i.GUID; connectionPointContainer.FindConnectionPoint(ref comappEventsInterfaceId, out var connectionPoint); connectionPoint.Advise(sink, out var cookie); connectionPoints.Add(new Tuple(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) { } private static Type[] GetComInterfaces(object sink) { var ii = sink?.GetType().GetInterfaces().ToList() ?? new List(); for (int i = ii.Count - 1; i >= 0; i--) { if (!ii[i].GetCustomAttributes(true).Any(a => a.GetType() == typeof(ComImportAttribute) || a.GetType() == typeof(InterfaceTypeAttribute))) ii.RemoveAt(i); } return ii.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(); } } }