diff --git a/Core/Extensions/InteropExtensions.cs b/Core/Extensions/InteropExtensions.cs
index 1bce8224..3be5d7a4 100644
--- a/Core/Extensions/InteropExtensions.cs
+++ b/Core/Extensions/InteropExtensions.cs
@@ -279,14 +279,21 @@ namespace Vanara.Extensions
///
/// The bytes allocated by the method.
/// Number of bytes preceding the trailing strings.
+ ///
+ /// The function used to lock memory before assignment. If , the result from will
+ /// be used.
+ ///
+ /// The optional function to unlock memory after assignment.
/// A pointer to the memory allocated by .
- public static IntPtr MarshalToPtr(this T value, Func memAlloc, out int bytesAllocated, int prefixBytes = 0)
+ public static IntPtr MarshalToPtr(this T value, Func memAlloc, out int bytesAllocated, int prefixBytes = 0, Func memLock = null, Action memUnlock = null)
{
+ memLock ??= Passthrough;
if (VanaraMarshaler.CanMarshal(typeof(T), out var marshaler))
{
using var mem = marshaler.MarshalManagedToNative(value);
var ret = memAlloc(bytesAllocated = mem.Size + prefixBytes);
- mem.DangerousGetHandle().CopyTo(ret.Offset(prefixBytes), mem.Size);
+ mem.DangerousGetHandle().CopyTo(memLock(ret).Offset(prefixBytes), mem.Size);
+ memUnlock?.Invoke(ret);
return ret;
}
else
@@ -294,11 +301,14 @@ namespace Vanara.Extensions
var newVal = TrueValue(value, out bytesAllocated);
bytesAllocated += prefixBytes;
var ret = memAlloc(bytesAllocated);
- Write(ret, newVal, prefixBytes, bytesAllocated);
+ Write(memLock(ret), newVal, prefixBytes, bytesAllocated);
+ memUnlock?.Invoke(ret);
return ret;
}
}
+ private static IntPtr Passthrough(IntPtr p) => p;
+
///
/// Marshals data from a managed list of specified type to an unmanaged block of memory allocated by the method.
///
@@ -312,12 +322,18 @@ namespace Vanara.Extensions
///
/// The bytes allocated by the method.
/// Number of bytes preceding the trailing strings.
+ ///
+ /// The function used to lock memory before assignment. If , the result from will
+ /// be used.
+ ///
+ /// The optional function to unlock memory after assignment.
/// Pointer to the allocated native (unmanaged) array of items stored.
/// Structure layout is not sequential or explicit.
- public static IntPtr MarshalToPtr(this IEnumerable items, Func memAlloc, out int bytesAllocated, int prefixBytes = 0)
+ public static IntPtr MarshalToPtr(this IEnumerable items, Func memAlloc, out int bytesAllocated, int prefixBytes = 0, Func memLock = null, Action memUnlock = null)
{
if (!typeof(T).IsMarshalable()) throw new ArgumentException(@"Structure layout is not sequential or explicit.");
+ memLock ??= Passthrough;
bytesAllocated = prefixBytes;
var count = items?.Count() ?? 0;
if (count == 0) return memAlloc(bytesAllocated);
@@ -325,7 +341,9 @@ namespace Vanara.Extensions
var sz = Marshal.SizeOf(typeof(T));
bytesAllocated += sz * count;
var result = memAlloc(bytesAllocated);
- result.Write(items, prefixBytes, bytesAllocated);
+ memLock(result).Write(items, prefixBytes, bytesAllocated);
+ memUnlock?.Invoke(result);
+
return result;
}
@@ -341,10 +359,15 @@ namespace Vanara.Extensions
///
/// The bytes allocated by the method.
/// Number of bytes preceding the trailing strings.
+ ///
+ /// The function used to lock memory before assignment. If , the result from will
+ /// be used.
+ ///
+ /// The optional function to unlock memory after assignment.
/// 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(items.Cast(), memAlloc, out bytesAllocated, prefixBytes);
+ public static IntPtr MarshalToPtr(this T[] items, Func memAlloc, out int bytesAllocated, int prefixBytes = 0, Func memLock = null, Action memUnlock = null) =>
+ MarshalToPtr(items.Cast(), memAlloc, out bytesAllocated, prefixBytes, memLock, memUnlock);
///
/// Marshals data from a managed list of strings to an unmanaged block of memory allocated by the method.
@@ -357,18 +380,26 @@ namespace Vanara.Extensions
/// The bytes allocated by the method.
/// The character set to use for the strings.
/// Number of bytes preceding the trailing strings.
+ ///
+ /// The function used to lock memory before assignment. If , the result from will
+ /// be used.
+ ///
+ /// The optional function to unlock memory after assignment.
///
/// Pointer to the allocated native (unmanaged) array of strings stored using the model and the character
/// set defined by .
///
- public static IntPtr MarshalToPtr(this IEnumerable values, StringListPackMethod packing, Func memAlloc, out int bytesAllocated, CharSet charSet = CharSet.Auto, int prefixBytes = 0)
+ public static IntPtr MarshalToPtr(this IEnumerable values, StringListPackMethod packing, Func memAlloc, out int bytesAllocated, CharSet charSet = CharSet.Auto, int prefixBytes = 0, Func memLock = null, Action memUnlock = null)
{
+ memLock ??= Passthrough;
+
// Bail early if empty
if (values is null || !values.Any())
{
bytesAllocated = prefixBytes + (packing == StringListPackMethod.Concatenated ? StringHelper.GetCharSize(charSet) : IntPtr.Size);
var ret = memAlloc(bytesAllocated);
- ret.FillMemory(0, bytesAllocated);
+ memLock(ret).FillMemory(0, bytesAllocated);
+ memUnlock?.Invoke(ret);
return ret;
}
@@ -396,7 +427,8 @@ namespace Vanara.Extensions
// Copy to newly allocated memory using memAlloc
bytesAllocated = (int)ms.Length;
var ret = memAlloc(bytesAllocated);
- ms.Pointer.CopyTo(ret, bytesAllocated);
+ ms.Pointer.CopyTo(memLock(ret), bytesAllocated);
+ memUnlock?.Invoke(ret);
return ret;
}
}
@@ -412,12 +444,17 @@ namespace Vanara.Extensions
/// The bytes allocated by the method.
/// The character set to use for the strings.
/// Number of bytes preceding the trailing strings.
+ ///
+ /// The function used to lock memory before assignment. If , the result from will
+ /// be used.
+ ///
+ /// The optional function to unlock memory after assignment.
///
/// Pointer to the allocated native (unmanaged) array of strings stored using the model and the character
/// set defined by .
///
- public static IntPtr MarshalToPtr(this string[] values, StringListPackMethod packing, Func memAlloc, out int bytesAllocated, CharSet charSet = CharSet.Auto, int prefixBytes = 0) =>
- MarshalToPtr((IEnumerable)values, packing, memAlloc, out bytesAllocated, charSet, prefixBytes);
+ public static IntPtr MarshalToPtr(this string[] values, StringListPackMethod packing, Func memAlloc, out int bytesAllocated, CharSet charSet = CharSet.Auto, int prefixBytes = 0, Func memLock = null, Action memUnlock = null) =>
+ MarshalToPtr((IEnumerable)values, packing, memAlloc, out bytesAllocated, charSet, prefixBytes, memLock, memUnlock);
/// Adds an offset to the value of a pointer.
/// The pointer to add the offset to.