diff --git a/Core/InteropServices/SafeIDispatch.cs b/Core/InteropServices/SafeIDispatch.cs new file mode 100644 index 00000000..9c288cd9 --- /dev/null +++ b/Core/InteropServices/SafeIDispatch.cs @@ -0,0 +1,59 @@ +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 + { + result = Marshal.GetIDispatchForObject(target); + } + finally + { + // Decrement reference count added by call to GetIDispatchForObject + if (result != IntPtr.Zero) + Marshal.Release(result); + } + return result; + } + } +} \ No newline at end of file