using System; using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace SpeechLib { /// Marshals the COM interface to the .NET Framework interface, and vice versa. public class EnumeratorToEnumVariantMarshaler : ICustomMarshaler { [ComImport] [Guid("00020404-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IEnumVARIANT { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] void Next(int celt, [MarshalAs(UnmanagedType.Struct)] out object rgvar, out uint pceltFetched); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] void Skip(uint celt); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] void Reset(); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [return: MarshalAs(UnmanagedType.Interface)] IEnumVARIANT Clone(); } private class VARIANTEnumerator : IEnumerator { private IEnumVARIANT com_enum; private object current; public object Current => current; public VARIANTEnumerator(IEnumVARIANT com_enum) { this.com_enum = com_enum; } public bool MoveNext() { uint pceltFetched = 0u; com_enum.Next(1, out var rgvar, out pceltFetched); if (pceltFetched == 0) { return false; } current = rgvar; return true; } public void Reset() { com_enum.Reset(); } } private static EnumeratorToEnumVariantMarshaler instance; /// Performs necessary cleanup of the managed data when it is no longer needed. /// The managed object to be destroyed. public void CleanUpManagedData(object pManagedObj) { throw new NotImplementedException(); } /// Performs necessary cleanup of the unmanaged data when it is no longer needed. /// A pointer to the unmanaged data to be destroyed. public void CleanUpNativeData(IntPtr pNativeData) { Marshal.Release(pNativeData); } /// Returns an instance of the custom marshaler. /// String "cookie" parameter that can be used by the custom marshaler. /// An instance of the custom marshaler. public static ICustomMarshaler GetInstance(string pstrCookie) { if (instance == null) { instance = new EnumeratorToEnumVariantMarshaler(); } return instance; } /// Returns the size in bytes of the unmanaged data to be marshaled. /// -1 to indicate the type this marshaler handles is not a value type. public int GetNativeDataSize() { throw new NotImplementedException(); } /// Marshals an object from managed code to unmanaged code. /// The managed object to be converted. /// A pointer to the unmanaged object. /// /// is . public IntPtr MarshalManagedToNative(object pManagedObj) { throw new NotImplementedException(); } /// Marshals an object from unmanaged code to managed code. /// A pointer to the unmanaged object to be converted. /// A managed object. /// /// is . /// The unmanaged object that points to could not be converted. public object MarshalNativeToManaged(IntPtr pNativeData) { return new VARIANTEnumerator((IEnumVARIANT)Marshal.GetObjectForIUnknown(pNativeData)); } } }