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;
}
}
}