diff --git a/Core/Extensions/InteropExtensions.cs b/Core/Extensions/InteropExtensions.cs index 17239eb3..c05efe13 100644 --- a/Core/Extensions/InteropExtensions.cs +++ b/Core/Extensions/InteropExtensions.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.Serialization; using System.Security; using System.Security.Permissions; +using Vanara.Extensions.Reflection; using Vanara.InteropServices; using Vanara.PInvoke; @@ -74,7 +76,7 @@ namespace Vanara.Extensions /// Determines whether this type is formatted or blittable. /// The type to check. - /// true if the specified type is blittable; otherwise, false. + /// if the specified type is blittable; otherwise, . public static bool IsBlittable(this Type T) { if (T is null) return false; @@ -98,9 +100,18 @@ namespace Vanara.Extensions try { Marshal.SizeOf(T); return true; } catch { return false; } } + /// Determines whether this type is marshalable. + /// The type to check. + /// if the specified type is marshalable; otherwise, . + public static bool IsMarshalable(this Type type) + { + var t = type.IsNullable() ? type.GetGenericArguments()[0] : type; + return t.IsSerializable || VanaraMarshaler.CanMarshal(t, out _) || t.IsBlittable(); + } + /// Determines whether this type is nullable (derived from ). /// The type to check. - /// true if the specified type is nullable; otherwise, false. + /// if the specified type is nullable; otherwise, . public static bool IsNullable(this Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); /// Marshals an unmanaged linked list of structures to an of that structure. @@ -227,7 +238,7 @@ namespace Vanara.Extensions /// Structure layout is not sequential or explicit. public static IntPtr MarshalToPtr(this IEnumerable items, Func memAlloc, out int bytesAllocated, int prefixBytes = 0) { - if (!typeof(T).IsBlittable()) throw new ArgumentException(@"Structure layout is not sequential or explicit."); + if (!typeof(T).IsMarshalable()) throw new ArgumentException(@"Structure layout is not sequential or explicit."); bytesAllocated = prefixBytes; var count = items?.Count() ?? 0; @@ -255,7 +266,7 @@ namespace Vanara.Extensions /// Pointer to the allocated native (unmanaged) array of items stored. /// Structure layout is not sequential or explicit. public static IntPtr MarshalToPtr(this T[] items, Func memAlloc, out int bytesAllocated, int prefixBytes = 0) => - MarshalToPtr((IEnumerable)items, memAlloc, out bytesAllocated, prefixBytes); + MarshalToPtr(items.Cast(), memAlloc, out bytesAllocated, prefixBytes); /// /// Marshals data from a managed list of strings to an unmanaged block of memory allocated by the method. @@ -648,17 +659,17 @@ namespace Vanara.Extensions var count = items?.Count() ?? 0; if (count == 0) return 0; - if (!typeof(T).IsBlittable()) + var ttype = TrueType(typeof(T), out var stSize); + if (!ttype.IsMarshalable()) throw new ArgumentException(@"Structure layout is not sequential or explicit."); - var ttype = TrueType(typeof(T), out var stSize); var bytesReq = stSize * count + offset; if (allocatedBytes > 0 && bytesReq > allocatedBytes) throw new InsufficientMemoryException(); var i = 0; - foreach (var item in items.Select(v => Convert.ChangeType(v, ttype))) - ptr.Write(item, offset + i++ * stSize, allocatedBytes); + foreach (var item in items.Select(v => Convert.ChangeType(v, ttype)).Where(v => v != null)) + WriteNoChecks(ptr, item, offset + i++ * stSize, allocatedBytes); return bytesReq - offset; } @@ -673,7 +684,7 @@ namespace Vanara.Extensions public static int Write(this IntPtr ptr, object value, int offset = 0, SizeT allocatedBytes = default) { if (value is null) return 0; - if (!value.GetType().IsBlittable()) + if (!value.GetType().IsMarshalable()) throw new ArgumentException(@"Value cannot be serialized to memory.", nameof(value)); return WriteNoChecks(ptr, value, offset, allocatedBytes); }