using System; using System.Runtime.InteropServices; namespace Vanara.InteropServices { /// Provide a IDispatch-based (e.g. late-bound) access to a COM object. Use to work with the object. public class SafeIDispatch : ComReleaser { /// Initializes a new instance of the class. /// The target object which must be a raw COM object. public SafeIDispatch(object target) : base(target) { if (!Marshal.IsComObject(target)) throw new ArgumentException("The target object must be a COM object"); RawPointer = GetRawPointer(target); } /// Gets the pointer to the IDispatch instance. /// A pointer to the IDispatch instance. public IntPtr RawPointer { get; } /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// if the specified is equal to this instance; otherwise, . public bool Equals(ComReleaser other) => other?.Item is null || Item is null ? false : (bool)(RawPointer == GetRawPointer(other.Item)); /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// if the specified is equal to this instance; otherwise, . public override bool Equals(object obj) => obj is ComReleaser o ? Equals(o) : base.Equals(obj); /// Returns a hash code for this instance. /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. public override int GetHashCode() => RawPointer.ToInt32(); /// /// Method to encapsulate operations against the late-bound COM object. The caller must handle any exceptions that may result as part /// of the operation. /// /// A method that performs work against the late-bound COM object. public void Invoke(Action action) => action.Invoke(Item); private static IntPtr GetRawPointer(object target) { var result = IntPtr.Zero; try { #if NETSTANDARD2_0 result = Marshal.GetComInterfaceForObject(target, typeof(IDispatch)); #else result = Marshal.GetIDispatchForObject(target); #endif } finally { // Decrement reference count added by call to GetIDispatchForObject if (result != IntPtr.Zero) Marshal.Release(result); } return result; } #if NETSTANDARD2_0 [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] private interface IDispatch { } #endif } }