using System.Collections.Generic; namespace System.Runtime.InteropServices { internal static class InteropUtil { internal const int cbBuffer = 256; [Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.LinkDemand, Flags = Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] public static T ToStructure(this IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T)); public static IntPtr StructureToPtr(this T value) where T : struct { var ret = Marshal.AllocHGlobal(Marshal.SizeOf(value)); Marshal.StructureToPtr(value, ret, false); return ret; } [Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.LinkDemand, Flags = Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] public static void AllocString(ref IntPtr ptr, ref uint size) { FreeString(ref ptr, ref size); if (size == 0) size = cbBuffer; ptr = Marshal.AllocHGlobal(cbBuffer); } [Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.LinkDemand, Flags = Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] public static void FreeString(ref IntPtr ptr, ref uint size) { if (ptr == IntPtr.Zero) return; Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; size = 0; } [Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.LinkDemand, Flags = Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] public static string GetString(IntPtr pString) => Marshal.PtrToStringUni(pString); [Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.LinkDemand, Flags = Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] public static bool SetString(ref IntPtr ptr, ref uint size, string value = null) { var s = GetString(ptr); if (value == string.Empty) value = null; if (string.CompareOrdinal(s, value) == 0) return false; FreeString(ref ptr, ref size); if (value == null) return true; ptr = Marshal.StringToHGlobalUni(value); size = (uint)value.Length + 1; return true; } /// /// Converts an that points to a C-style array into a CLI array. /// /// Type of native structure used by the C-style array. /// Output type for the CLI array. must be able to convert to . /// The pointing to the native array. /// The number of items in the native array. /// Bytes to skip before reading the array. /// An array of type containing the converted elements of the native array. public static T[] ToArray(this IntPtr ptr, int count, int prefixBytes = 0) where TS : IConvertible { var ret = new T[count]; var stSize = Marshal.SizeOf(typeof(TS)); for (var i = 0; i < count; i++) { var val = ToStructure(Marshal.ReadIntPtr(ptr, prefixBytes + i * stSize)); ret[i] = (T)Convert.ChangeType(val, typeof(T)); } return ret; } /// /// Converts an that points to a C-style array into a CLI array. /// /// Type of native structure used by the C-style array. /// The pointing to the native array. /// The number of items in the native array. /// Bytes to skip before reading the array. /// An array of type containing the elements of the native array. public static T[] ToArray(this IntPtr ptr, int count, int prefixBytes = 0) { var ret = new T[count]; var stSize = Marshal.SizeOf(typeof(T)); for (var i = 0; i < count; i++) ret[i] = ToStructure(Marshal.ReadIntPtr(ptr, prefixBytes + i * stSize)); return ret; } /// /// Converts an that points to a C-style array into an . /// /// Type of native structure used by the C-style array. /// The pointing to the native array. /// The number of items in the native array. /// Bytes to skip before reading the array. /// An exposing the elements of the native array. public static IEnumerable ToIEnum(this IntPtr ptr, int count, int prefixBytes = 0) { if (count == 0) yield break; var stSize = Marshal.SizeOf(typeof(T)); for (var i = 0; i < count; i++) yield return ToStructure(Marshal.ReadIntPtr(ptr, prefixBytes + i * stSize)); } /// /// Converts an to a structure. If pointer has no value, null is returned. /// /// Type of the structure. /// The that points to allocated memory holding a structure or . /// The converted structure or null. public static T? PtrToStructure(this IntPtr ptr) where T : struct => ptr != IntPtr.Zero ? ptr.ToStructure() : (T?)null; /// /// Converts a structure or null value to an . If memory has not been allocated for the , it will be via a call to . /// /// Type of the structure. /// The structure to convert. If this value is null, will be set to and memory will be released. /// The that will point to allocated memory holding the structure or . /// An optional predicate check to determine if the structure is non-essential and can be replaced with an empty pointer (null). public static void StructureToPtr(T? value, ref IntPtr ptr, Predicate isEmpty = null) where T : struct { if (value == null || (isEmpty != null && isEmpty(value.Value))) { if (ptr == IntPtr.Zero) return; Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; } else { if (ptr == IntPtr.Zero) ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T))); Marshal.StructureToPtr(value, ptr, false); } } } }