From c0d841f06dd9ac4ca60a01f8424b47386ab3e2dd Mon Sep 17 00:00:00 2001 From: David Hall Date: Tue, 22 Oct 2019 08:27:07 -0600 Subject: [PATCH] Added IEnumUnknown generics implementation --- PInvoke/Ole/Ole32/ObjIdl.cs | 98 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/PInvoke/Ole/Ole32/ObjIdl.cs b/PInvoke/Ole/Ole32/ObjIdl.cs index 1e9335d9..79a90098 100644 --- a/PInvoke/Ole/Ole32/ObjIdl.cs +++ b/PInvoke/Ole/Ole32/ObjIdl.cs @@ -4364,5 +4364,103 @@ namespace Vanara.PInvoke /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. void IDisposable.Dispose() => ptr?.Dispose(); } + + /// Simple generic implementation of . + /// The type to enumerate. + /// + /// + public class IEnumUnknownImpl : IReadOnlyList, IEnumUnknown where T : class + { + private int current = -1; + private List items; + + /// Initializes a new instance of the class using an existing enumeration. + /// The items to enumerate. + /// items + public IEnumUnknownImpl(IEnumerable items) + { + this.items = new List(items ?? throw new ArgumentNullException(nameof(items))); + } + + /// Gets the element at the specified index in the read-only list. + /// The element at the specified index in the read-only list. + /// The zero-based index of the element to get. + public T this[int index] => items[index]; + + /// Gets the number of elements in the collection. + /// The number of elements in the collection. + public int Count => items.Count; + + /// Retrieves the specified number of items in the enumeration sequence. + /// + /// The number of items to be retrieved. If there are fewer than the requested number of items left in the sequence, this method + /// retrieves the remaining elements. + /// + /// + /// An array of enumerated items. + /// + /// The enumerator is responsible for calling AddRef, and the caller is responsible for calling Release through each pointer + /// enumerated. If celt is greater than 1, the caller must also pass a non-NULL pointer passed to pceltFetched to know how many + /// pointers to release. + /// + /// + /// + /// The number of items that were retrieved. This parameter is always less than or equal to the number of items requested. + /// + /// If the method retrieves the number of items requested, the return value is S_OK. Otherwise, it is S_FALSE. + /// rgelt - The length is not large enough for the requested number of items. + HRESULT IEnumUnknown.Next(uint celt, IntPtr[] rgelt, out uint pceltFetched) + { + pceltFetched = 0; + if (++current < items.Count) + { + pceltFetched = Math.Min((uint)(items.Count - current), celt); + if (rgelt is null || rgelt.Length < pceltFetched) + throw new ArgumentOutOfRangeException(nameof(rgelt), "The length is not large enough for the requested number of items."); + for (int i = 0; i < pceltFetched; i++) + rgelt[i] = Marshal.GetIUnknownForObject(items[current + i]); + return HRESULT.S_OK; + } + return HRESULT.S_FALSE; + } + + /// Skips over the specified number of items in the enumeration sequence. + /// The number of items to be skipped. + /// If the method skips the number of items requested, the return value is S_OK. Otherwise, it is S_FALSE. + HRESULT IEnumUnknown.Skip(uint celt) + { + var temp = current + (int)celt; + if (temp > items.Count - 1) + return HRESULT.S_FALSE; + current = temp; + return HRESULT.S_OK; + } + + /// Resets the enumeration sequence to the beginning. + /// + /// There is no guarantee that the same set of objects will be enumerated after the reset operation has completed. A static + /// collection is reset to the beginning, but it can be too expensive for some collections, such as files in a directory, to + /// guarantee this condition. + /// + void IEnumUnknown.Reset() => current = -1; + + /// + /// Creates a new enumerator that contains the same enumeration state as the current one. + /// + /// This method makes it possible to record a point in the enumeration sequence in order to return to that point at a later time. + /// The caller must release this new enumerator separately from the first enumerator. + /// + /// + /// A pointer to the cloned enumerator object. + IEnumUnknown IEnumUnknown.Clone() => new IEnumUnknownImpl(items); + + /// Returns an enumerator that iterates through the collection. + /// A that can be used to iterate through the collection. + public IEnumerator GetEnumerator() => items.GetEnumerator(); + + /// Returns an enumerator that iterates through a collection. + /// An object that can be used to iterate through the collection. + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + } } } \ No newline at end of file