mirror of https://github.com/dahall/Vanara.git
Added Write methods to SafeMemoryHandleExt. Added size checking from InteropExtension methods. Added offset param to ToStructure.
parent
d03c88b931
commit
9d4758ed5d
|
@ -173,8 +173,8 @@ namespace Vanara.Extensions
|
|||
/// </typeparam>
|
||||
/// <param name="items">The enumerated list of items to marshal.</param>
|
||||
/// <param name="ptr">
|
||||
/// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of <typeparamref
|
||||
/// name="T"/> times the number of items in the enumeration plus the number of bytes specified by <paramref name="prefixBytes"/>.
|
||||
/// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of
|
||||
/// <typeparamref name="T"/> times the number of items in the enumeration plus the number of bytes specified by <paramref name="prefixBytes"/>.
|
||||
/// </param>
|
||||
/// <param name="prefixBytes">The number of bytes to skip before writing the first element of <paramref name="items"/>.</param>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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()); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshals data from a managed list of specified type to a pre-allocated unmanaged block of memory.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">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.</typeparam>
|
||||
/// <param name="ptr">A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of
|
||||
/// <typeparamref name="T" /> times the number of items in the enumeration plus the number of bytes specified by <paramref name="offset" />.</param>
|
||||
/// <summary>Marshals data from a managed list of specified type to a pre-allocated unmanaged block of memory.</summary>
|
||||
/// <typeparam name="T">
|
||||
/// 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.
|
||||
/// </typeparam>
|
||||
/// <param name="ptr">
|
||||
/// A pointer to a pre-allocated block of memory. The allocated memory must be sufficient to hold the size of
|
||||
/// <typeparamref name="T"/> times the number of items in the enumeration plus the number of bytes specified by <paramref name="offset"/>.
|
||||
/// </param>
|
||||
/// <param name="items">The enumerated list of items to marshal.</param>
|
||||
/// <param name="offset">The number of bytes to skip before writing the first element of <paramref name="items" />.</param>
|
||||
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory in <paramref name="ptr" />.</param>
|
||||
/// <param name="offset">The number of bytes to skip before writing the first element of <paramref name="items"/>.</param>
|
||||
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory in <paramref name="ptr"/>.</param>
|
||||
/// <returns>The number of bytes written. The offset is not included.</returns>
|
||||
/// <exception cref="ArgumentException">Structure layout is not sequential or explicit.</exception>
|
||||
/// <exception cref="InsufficientMemoryException"></exception>
|
||||
public static void Write<T>(this IntPtr ptr, IEnumerable<T> items, int offset = 0, SizeT allocatedBytes = default)
|
||||
public static int Write<T>(this IntPtr ptr, IEnumerable<T> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to pre-allocated memory.
|
||||
/// </summary>
|
||||
/// <summary>Writes the specified value to pre-allocated memory.</summary>
|
||||
/// <param name="ptr">The address of the memory where the value is to be written.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
/// <param name="offset">The number of bytes to offset from <paramref name="ptr" /> before writing.</param>
|
||||
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory in <paramref name="ptr" />.</param>
|
||||
/// <returns>
|
||||
/// The number of bytes written. The offset is not included.
|
||||
/// </returns>
|
||||
/// <param name="offset">The number of bytes to offset from <paramref name="ptr"/> before writing.</param>
|
||||
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory in <paramref name="ptr"/>.</param>
|
||||
/// <returns>The number of bytes written. The offset is not included.</returns>
|
||||
/// <exception cref="InsufficientMemoryException"></exception>
|
||||
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<T>(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<T>(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)
|
||||
|
|
|
@ -116,8 +116,9 @@ namespace Vanara.InteropServices
|
|||
|
||||
/// <summary>Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter.</summary>
|
||||
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a structure.</typeparam>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the structure.</param>
|
||||
/// <returns>A managed object that contains the data that this <see cref="SafeMemoryHandleExt{T}"/> holds.</returns>
|
||||
T ToStructure<T>();
|
||||
T ToStructure<T>(int prefixBytes = 0);
|
||||
}
|
||||
|
||||
/// <summary>Abstract base class for all SafeHandle derivatives that encapsulate handling unmanaged memory.</summary>
|
||||
|
@ -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<T>(count, prefixBytes);
|
||||
return handle.ToArray<T>(count, prefixBytes, sz);
|
||||
}
|
||||
|
||||
/// <summary>Extracts an enumeration of structures of <typeparamref name="T"/> containing <paramref name="count"/> 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<T>(count, prefixBytes);
|
||||
return handle.ToIEnum<T>(count, prefixBytes, sz);
|
||||
}
|
||||
|
||||
/// <summary>Returns a <see cref="System.String"/> that represents this instance.</summary>
|
||||
/// <param name="len">The length.</param>
|
||||
/// <param name="charSet">The character set of the string.</param>
|
||||
/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
|
||||
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);
|
||||
|
||||
/// <summary>Returns an enumeration of strings from memory where each string is pointed to by a preceding list of pointers of length <paramref name="count"/>.</summary>
|
||||
/// <param name="count">The count of expected strings.</param>
|
||||
/// <param name="charSet">The character set of the strings.</param>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the array of string pointers.</param>
|
||||
/// <returns>Enumeration of strings.</returns>
|
||||
public IEnumerable<string> ToStringEnum(int count, CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(count, charSet, prefixBytes);
|
||||
public IEnumerable<string> ToStringEnum(int count, CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(count, charSet, prefixBytes, sz);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
|||
/// <param name="charSet">The character set of the strings.</param>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the array of string pointers.</param>
|
||||
/// <returns>An enumerated list of strings.</returns>
|
||||
public IEnumerable<string> ToStringEnum(CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(charSet, prefixBytes);
|
||||
public IEnumerable<string> ToStringEnum(CharSet charSet = CharSet.Auto, int prefixBytes = 0) => IsInvalid ? new string[0] : handle.ToStringEnum(charSet, prefixBytes, sz);
|
||||
|
||||
/// <summary>Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter.</summary>
|
||||
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a structure.</typeparam>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the structure.</param>
|
||||
/// <returns>A managed object that contains the data that this <see cref="SafeMemoryHandleExt{T}"/> holds.</returns>
|
||||
public T ToStructure<T>()
|
||||
public T ToStructure<T>(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<T>();
|
||||
return handle.ToStructure<T>(sz, prefixBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshals data from a managed list of specified type to an offset within this allocated memory.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">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.</typeparam>
|
||||
/// <param name="items">The enumerated list of items to marshal.</param>
|
||||
/// <param name="autoExtend">if set to <c>true</c> automatically extend the allocated memory to the size required to hold <paramref name="items"/>.</param>
|
||||
/// <param name="offset">The number of bytes to skip before writing the first element of <paramref name="items" />.</param>
|
||||
public void Write<T>(IEnumerable<T> 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);
|
||||
}
|
||||
|
||||
/// <summary>Writes the specified value to an offset within this allocated memory.</summary>
|
||||
/// <typeparam name="T">The type of the value to write.</typeparam>
|
||||
/// <param name="value">The value to write.</param>
|
||||
/// <param name="autoExtend">if set to <c>true</c> automatically extend the allocated memory to the size required to hold <paramref name="value"/>.</param>
|
||||
/// <param name="offset">The number of bytes to offset from the beginning of this allocated memory before writing.</param>
|
||||
public void Write<T>(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);
|
||||
}
|
||||
|
||||
/// <summary>When overridden in a derived class, executes the code required to free the handle.</summary>
|
||||
|
|
Loading…
Reference in New Issue