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