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);
}