diff --git a/Core/Extensions/InteropExtensions.cs b/Core/Extensions/InteropExtensions.cs
index a77578be..65e4e32a 100644
--- a/Core/Extensions/InteropExtensions.cs
+++ b/Core/Extensions/InteropExtensions.cs
@@ -173,8 +173,8 @@ namespace Vanara.Extensions
///
/// The enumerated list of items to marshal.
///
- /// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of times the number of items in the enumeration plus the number of bytes specified by .
+ /// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of
+ /// times the number of items in the enumeration plus the number of bytes specified by .
///
/// The number of bytes to skip before writing the first element of .
[Obsolete("Please use the Vanara.Extensions.InteropExtensions.Write method instead. This will be removed from the library shortly as it performs no allocation.", true)]
@@ -540,7 +540,10 @@ namespace Vanara.Extensions
}
if (i + charLength > allocatedBytes) throw new InsufficientMemoryException();
- int GetCh(IntPtr p) => charLength == 1 ? Marshal.ReadByte(p) : Marshal.ReadInt16(p);
+ int GetCh(IntPtr p)
+ {
+ return charLength == 1 ? Marshal.ReadByte(p) : Marshal.ReadInt16(p);
+ }
}
///
@@ -576,7 +579,7 @@ namespace Vanara.Extensions
if (allocatedBytes > 0 && allocatedBytes < stSize + offset)
throw new InsufficientMemoryException();
if (t == typeof(T))
- Marshal.PtrToStructure(ptr, (object)instance);
+ Marshal.PtrToStructure(ptr, instance);
else
using (var pin = new PinnedObject(instance))
((IntPtr)pin).Write(Marshal.PtrToStructure(ptr.Offset(offset), t));
@@ -598,22 +601,25 @@ namespace Vanara.Extensions
unsafe { return new UIntPtr(p.ToPointer()); }
}
- ///
- /// Marshals data from a managed list of specified type to a pre-allocated unmanaged block of memory.
- ///
- /// A type of the enumerated managed object that holds the data to be marshaled. The object must be a structure or an instance of a
- /// formatted class.
- /// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of
- /// times the number of items in the enumeration plus the number of bytes specified by .
+ /// Marshals data from a managed list of specified type to a pre-allocated unmanaged block of memory.
+ ///
+ /// A type of the enumerated managed object that holds the data to be marshaled. The object must be a structure or an instance of a
+ /// formatted class.
+ ///
+ ///
+ /// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of
+ /// times the number of items in the enumeration plus the number of bytes specified by .
+ ///
/// The enumerated list of items to marshal.
- /// The number of bytes to skip before writing the first element of .
- /// If known, the total number of bytes allocated to the native memory in .
+ /// The number of bytes to skip before writing the first element of .
+ /// If known, the total number of bytes allocated to the native memory in .
+ /// The number of bytes written. The offset is not included.
/// Structure layout is not sequential or explicit.
///
- public static void Write(this IntPtr ptr, IEnumerable items, int offset = 0, SizeT allocatedBytes = default)
+ public static int Write(this IntPtr ptr, IEnumerable items, int offset = 0, SizeT allocatedBytes = default)
{
var count = items?.Count() ?? 0;
- if (count == 0) return;
+ if (count == 0) return 0;
if (!typeof(T).IsBlittable())
throw new ArgumentException(@"Structure layout is not sequential or explicit.");
@@ -626,18 +632,16 @@ namespace Vanara.Extensions
var i = 0;
foreach (var item in items.Select(v => Convert.ChangeType(v, ttype)))
Marshal.StructureToPtr(item, ptr.Offset(offset + i++ * stSize), false);
+
+ return bytesReq - offset;
}
- ///
- /// Writes the specified value to pre-allocated memory.
- ///
+ /// Writes the specified value to pre-allocated memory.
/// The address of the memory where the value is to be written.
/// The value to write.
- /// The number of bytes to offset from before writing.
- /// If known, the total number of bytes allocated to the native memory in .
- ///
- /// The number of bytes written. The offset is not included.
- ///
+ /// The number of bytes to offset from before writing.
+ /// If known, the total number of bytes allocated to the native memory in .
+ /// The number of bytes written. The offset is not included.
///
public static int Write(this IntPtr ptr, object value, int offset = 0, SizeT allocatedBytes = default)
{
@@ -658,8 +662,15 @@ namespace Vanara.Extensions
public static int Write(this IntPtr ptr, T value, int offset = 0, SizeT allocatedBytes = default) where T : struct =>
WriteNoChecks(ptr, value, offset, allocatedBytes);
+ internal static Type TrueType(Type type, out int size)
+ {
+ var ttype = type.IsEnum ? Enum.GetUnderlyingType(type) : type;
+ size = Marshal.SizeOf(ttype);
+ return ttype;
+ }
+
private static T GetValueType(IntPtr ptr, Type trueType = null, int offset = 0) =>
- (T)GetValueType(ptr, typeof(T), trueType, offset);
+ (T)GetValueType(ptr, typeof(T), trueType, offset);
private static object GetValueType(IntPtr ptr, Type type, Type trueType = null, int offset = 0)
{
@@ -673,13 +684,6 @@ namespace Vanara.Extensions
return Convert.ChangeType(obj, type);
}
- private static Type TrueType(Type type, out int size)
- {
- var ttype = type.IsEnum ? Enum.GetUnderlyingType(type) : type;
- size = Marshal.SizeOf(ttype);
- return ttype;
- }
-
private static object TrueValue(object value, out int size) => Convert.ChangeType(value, TrueType(value.GetType(), out size));
private static int WriteNoChecks(IntPtr ptr, object value, int offset, SizeT allocatedBytes)
diff --git a/Core/InteropServices/SafeMemoryHandle.cs b/Core/InteropServices/SafeMemoryHandle.cs
index d45b5e2d..d410d633 100644
--- a/Core/InteropServices/SafeMemoryHandle.cs
+++ b/Core/InteropServices/SafeMemoryHandle.cs
@@ -116,8 +116,9 @@ namespace Vanara.InteropServices
/// Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter.
/// The type of the object to which the data is to be copied. This must be a structure.
+ /// Number of bytes preceding the structure.
/// A managed object that contains the data that this holds.
- T ToStructure();
+ T ToStructure(int prefixBytes = 0);
}
/// Abstract base class for all SafeHandle derivatives that encapsulate handling unmanaged memory.
@@ -327,7 +328,7 @@ namespace Vanara.InteropServices
// throw new InsufficientMemoryException("Requested array is larger than the memory allocated.");
if (!typeof(T).IsBlittable()) throw new ArgumentException(@"Structure layout is not sequential or explicit.");
Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential);
- return handle.ToArray(count, prefixBytes);
+ return handle.ToArray(count, prefixBytes, sz);
}
/// Extracts an enumeration of structures of containing items.
@@ -344,21 +345,21 @@ namespace Vanara.InteropServices
// throw new InsufficientMemoryException("Requested array is larger than the memory allocated.");
if (!typeof(T).IsBlittable()) throw new ArgumentException(@"Structure layout is not sequential or explicit.");
Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential);
- return handle.ToIEnum(count, prefixBytes);
+ return handle.ToIEnum(count, prefixBytes, sz);
}
/// Returns a that represents this instance.
/// The length.
/// The character set of the string.
/// A that represents this instance.
- public string ToString(int len, CharSet charSet = CharSet.Unicode) => len == -1 ? StringHelper.GetString(handle, charSet) : StringHelper.GetString(handle, charSet).Substring(0, len);
+ public string ToString(int len, CharSet charSet = CharSet.Unicode) => len == -1 ? StringHelper.GetString(handle, charSet) : StringHelper.GetString(handle, charSet, sz).Substring(0, len);
/// Returns an enumeration of strings from memory where each string is pointed to by a preceding list of pointers of length .
/// The count of expected strings.
/// The character set of the strings.
/// Number of bytes preceding the array of string pointers.
/// Enumeration of strings.
- public IEnumerable ToStringEnum(int count, CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(count, charSet, prefixBytes);
+ public IEnumerable ToStringEnum(int count, CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(count, charSet, prefixBytes, sz);
///
/// Gets an enumerated list of strings from a block of unmanaged memory where each string is separated by a single '\0' character and is terminated by
@@ -367,17 +368,57 @@ namespace Vanara.InteropServices
/// The character set of the strings.
/// Number of bytes preceding the array of string pointers.
/// An enumerated list of strings.
- public IEnumerable ToStringEnum(CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(charSet, prefixBytes);
+ public IEnumerable ToStringEnum(CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(charSet, prefixBytes, sz);
/// Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter.
/// The type of the object to which the data is to be copied. This must be a structure.
+ /// Number of bytes preceding the structure.
/// A managed object that contains the data that this holds.
- public T ToStructure()
+ public T ToStructure(int prefixBytes = 0)
{
if (IsInvalid) return default;
- //if (Size < Marshal.SizeOf(typeof(T)))
- // throw new InsufficientMemoryException("Requested structure is larger than the memory allocated.");
- return handle.ToStructure();
+ return handle.ToStructure(sz, prefixBytes);
+ }
+
+ ///
+ /// Marshals data from a managed list of specified type to an offset within this allocated memory.
+ ///
+ /// A type of the enumerated managed object that holds the data to be marshaled. The object must be a structure or an instance of a
+ /// formatted class.
+ /// The enumerated list of items to marshal.
+ /// if set to true automatically extend the allocated memory to the size required to hold .
+ /// The number of bytes to skip before writing the first element of .
+ public void Write(IEnumerable items, bool autoExtend = true, int offset = 0)
+ {
+ if (IsInvalid) throw new MemberAccessException("Safe memory pointer is not valid.");
+ if (autoExtend)
+ {
+ var count = items?.Count() ?? 0;
+ if (count == 0) return;
+ InteropExtensions.TrueType(typeof(T), out var iSz);
+ var reqSz = iSz * count + offset;
+ if (sz < reqSz)
+ Size = reqSz;
+ }
+ handle.Write(items, offset, sz);
+ }
+
+ /// Writes the specified value to an offset within this allocated memory.
+ /// The type of the value to write.
+ /// The value to write.
+ /// if set to true automatically extend the allocated memory to the size required to hold .
+ /// The number of bytes to offset from the beginning of this allocated memory before writing.
+ public void Write(T value, bool autoExtend = true, int offset = 0) where T : struct
+ {
+ if (IsInvalid) throw new MemberAccessException("Safe memory pointer is not valid.");
+ if (autoExtend)
+ {
+ InteropExtensions.TrueType(typeof(T), out var iSz);
+ var reqSz = iSz + offset;
+ if (sz < reqSz)
+ Size = reqSz;
+ }
+ handle.Write(value, offset, sz);
}
/// When overridden in a derived class, executes the code required to free the handle.