From 4fa2755085ed75ea12f6e497951f8250a3b644c4 Mon Sep 17 00:00:00 2001 From: dahall Date: Mon, 14 Dec 2020 15:57:23 -0700 Subject: [PATCH] Added IArrayStruct interface to identify two-field structures where the first field is an UInt32 and the second is a pointer to an array of structures along with supporting marshaler and extension method. --- Core/Collections/IArrayStruct.cs | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Core/Collections/IArrayStruct.cs diff --git a/Core/Collections/IArrayStruct.cs b/Core/Collections/IArrayStruct.cs new file mode 100644 index 00000000..b4a35c96 --- /dev/null +++ b/Core/Collections/IArrayStruct.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Vanara.Extensions; +using Vanara.InteropServices; + +namespace Vanara.PInvoke +{ + /// + /// Interface that identifies a structure containing only a 4-byte size field followed by a pointer to an array of . + /// + /// A marshalable structure. + public interface IArrayStruct where T : struct { } + + /// Extension methods for . + public static class IArrayStructExtensions + { + /// Gets the array from an instance. + /// The type of the array. + /// The instance. + /// The array contained in the instance. + public static T[] GetArray(this IArrayStruct ias) where T : struct + { + using var pin = new PinnedObject(ias); + return ((IntPtr)pin).ToArray((int)((IntPtr)pin).ToStructure(), sizeof(uint)); + } + } + + /// Allows marshaling of arrays in place of a structure supporting . + /// The type of the array element. + /// + public class IArrayStructMarshaler : IVanaraMarshaler where T : struct + { + public static readonly int hSz = sizeof(uint); + + /// + public SizeT GetNativeSize() => hSz + IntPtr.Size; + + /// + public SafeAllocatedMemoryHandle MarshalManagedToNative(object managedObject) + { + if (managedObject is IEnumerable ias) + { + var cnt = ias.Count(); + var mem = new SafeHGlobalHandle(hSz + InteropExtensions.SizeOf() * cnt); + mem.Write(cnt); + mem.Write(ias, true, hSz); + return mem; + } + throw new ArgumentException("Unexpected type. Value must be of IEnumerable."); + } + + /// + public object MarshalNativeToManaged(IntPtr pNativeData, SizeT allocatedBytes) + { + if (pNativeData == default) return new T[0]; + var cnt = pNativeData.ToStructure(); + return pNativeData.ToArray((int)cnt, hSz, allocatedBytes); + } + } +} \ No newline at end of file