diff --git a/Core/InteropServices/SafeMemoryHandle.cs b/Core/InteropServices/SafeMemoryHandle.cs index cabcf84b..bc869a25 100644 --- a/Core/InteropServices/SafeMemoryHandle.cs +++ b/Core/InteropServices/SafeMemoryHandle.cs @@ -16,16 +16,17 @@ namespace Vanara.InteropServices { /// Each string is separated by a single '\0' character and is terminated by two '\0' characters. Concatenated, - /// A contiguous block of memory containing an array of pointers to strings followed by a NULL pointer and then followed by the actual strings. + + /// + /// A contiguous block of memory containing an array of pointers to strings followed by a NULL pointer and then followed by the + /// actual strings. + /// Packed } /// Interface to capture unmanaged memory methods. - public interface IMemoryMethods + public interface IMemoryMethods : ISimpleMemoryMethods { - /// Gets the allocation method. - Func AllocMem { get; } - /// Gets the Ansi allocation method. Func AllocSecureStringAnsi { get; } @@ -38,9 +39,6 @@ namespace Vanara.InteropServices /// Gets the Unicode string allocation method. Func AllocStringUni { get; } - /// Gets the free method. - Action FreeMem { get; } - /// Gets the Ansi free method. Action FreeSecureStringAnsi { get; } @@ -62,8 +60,9 @@ namespace Vanara.InteropServices SizeT Size { get; set; } /// - /// Adds reference to other SafeMemoryHandle objects, the pointer to which are referred to by this object. This is to ensure that such objects being - /// referred to wouldn't be unreferenced until this object is active. For e.g. when this object is an array of pointers to other objects + /// Adds reference to other SafeMemoryHandle objects, the pointer to which are referred to by this object. This is to ensure that + /// such objects being referred to wouldn't be unreferenced until this object is active. For e.g. when this object is an array of + /// pointers to other objects /// /// Collection of SafeMemoryHandle objects referred to by this object. void AddSubReference(IEnumerable children); @@ -73,8 +72,8 @@ namespace Vanara.InteropServices IntPtr DangerousGetHandle(); /// - /// Extracts an array of structures of containing items. This call can cause memory - /// exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. + /// Extracts an array of structures of containing items. This + /// call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. /// /// The type of the structures to retrieve. /// The number of structures to retrieve. @@ -83,8 +82,8 @@ namespace Vanara.InteropServices T[] ToArray(int count, int prefixBytes = 0); /// - /// Extracts an enumeration of structures of containing items. This call can cause - /// memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. + /// Extracts an enumeration of structures of containing items. This call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. /// /// The type of the structures to retrieve. /// The number of structures to retrieve. @@ -106,28 +105,80 @@ namespace Vanara.InteropServices string ToString(int len, int prefixBytes, CharSet charSet = CharSet.Unicode); /// - /// 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 - /// two '\0' characters. + /// 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 two '\0' characters. /// /// The character set of the strings. /// Number of bytes preceding the array of string pointers. /// Enumeration of strings. IEnumerable ToStringEnum(CharSet charSet = CharSet.Auto, int prefixBytes = 0); - /// Returns an enumeration of strings from memory where each string is pointed to by a preceding list of pointers of length . + /// + /// Returns an enumeration of strings from memory where each string is pointed to by a preceding list of pointers of length + /// . + /// /// The count. /// The character set of the strings. /// Number of bytes preceding the array of string pointers. /// An enumerated list of strings. IEnumerable ToStringEnum(int count, CharSet charSet = CharSet.Auto, int prefixBytes = 0); - /// Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter. + /// + /// 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(int prefixBytes = 0); } + /// Interface to capture unmanaged simple (alloc/free) memory methods. + public interface ISimpleMemoryMethods + { + /// Gets the allocation method. + Func AllocMem { get; } + + /// Gets the free method. + Action FreeMem { get; } + } + + /// Implementation of using just the methods from . + /// The type of the simple. + /// + public class MemoryMethodsFromSimple : IMemoryMethods where TSimple : ISimpleMemoryMethods, new() + { + /// A static instance of TSimple. + public static TSimple SimpleInstance = new TSimple(); + + /// Gets the Ansi allocation method. + public Func AllocSecureStringAnsi => s => StringHelper.AllocSecureString(s, CharSet.Ansi, AllocMem); + + /// Gets the Unicode allocation method. + public Func AllocSecureStringUni => s => StringHelper.AllocSecureString(s, CharSet.Unicode, AllocMem); + + /// Gets the Ansi string allocation method. + public Func AllocStringAnsi => s => StringHelper.AllocString(s, CharSet.Ansi, AllocMem); + + /// Gets the Unicode string allocation method. + public Func AllocStringUni => s => StringHelper.AllocString(s, CharSet.Unicode, AllocMem); + + /// Gets the Ansi free method. + public Action FreeSecureStringAnsi => FreeMem; + + /// Gets the Unicode free method. + public Action FreeSecureStringUni => FreeMem; + + /// Gets the reallocation method. + /// + public Func ReAllocMem => throw new NotImplementedException(); + + /// Gets the allocation method. + public Func AllocMem => SimpleInstance.AllocMem; + + /// Gets the free method. + public Action FreeMem => SimpleInstance.FreeMem; + } + /// Abstract base class for all SafeHandle derivatives that encapsulate handling unmanaged memory. /// public abstract class SafeAllocatedMemoryHandle : SafeHandle @@ -137,16 +188,32 @@ namespace Vanara.InteropServices /// if set to true if this class is responsible for freeing the memory on disposal. protected SafeAllocatedMemoryHandle(IntPtr handle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle) => SetHandle(handle); + /// Dumps memory to byte string. + [ExcludeFromCodeCoverage] + public string Dump => Size == 0 ? "" : string.Join(" ", GetBytes(0, Size).Select(b => b.ToString("X2")).ToArray()); + /// Gets or sets the size in bytes of the allocated memory block. /// The size in bytes of the allocated memory block. public abstract SizeT Size { get; set; } #if DEBUG - /// Dumps memory to byte string. - [ExcludeFromCodeCoverage] - public string Dump => Size == 0 ? "" : string.Join(" ", GetBytes(0, Size).Select(b => b.ToString("X2")).ToArray()); #endif + /// Performs an explicit conversion from to pointer. + /// The instance. + /// The result of the conversion. + public static unsafe explicit operator byte*(SafeAllocatedMemoryHandle hMem) => (byte*)hMem.handle; + + /// Performs an explicit conversion from to . + /// The instance. + /// The result of the conversion. + public static explicit operator SafeBuffer(SafeAllocatedMemoryHandle hMem) => new SafeBufferImpl(hMem); + + /// Performs an implicit conversion from to . + /// The instance. + /// The result of the conversion. + public static implicit operator IntPtr(SafeAllocatedMemoryHandle hMem) => hMem.handle; + /// Fills the allocated memory with a specific byte value. /// The byte value. public virtual void Fill(byte value) => Fill(value, Size); @@ -186,21 +253,6 @@ namespace Vanara.InteropServices return ret; } - /// Performs an explicit conversion from to . - /// The instance. - /// The result of the conversion. - public static explicit operator SafeBuffer(SafeAllocatedMemoryHandle hMem) => new SafeBufferImpl(hMem); - - /// Performs an explicit conversion from to pointer. - /// The instance. - /// The result of the conversion. - public static unsafe explicit operator byte*(SafeAllocatedMemoryHandle hMem) => (byte*)hMem.handle; - - /// Performs an implicit conversion from to . - /// The instance. - /// The result of the conversion. - public static implicit operator IntPtr(SafeAllocatedMemoryHandle hMem) => hMem.handle; - private class SafeBufferImpl : SafeBuffer { public SafeBufferImpl(SafeAllocatedMemoryHandle hMem) : base(false) => Initialize((ulong)hMem.Size); @@ -235,7 +287,10 @@ namespace Vanara.InteropServices /// if set to true if this class is responsible for freeing the memory on disposal. protected SafeMemoryHandle(IntPtr handle, SizeT size, bool ownsHandle) : base(handle, ownsHandle) => sz = size; - /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native array equivalent. + /// + /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native + /// array equivalent. + /// /// Array of unmanaged pointers /// SafeHGlobalHandle object to an native (unmanaged) array of pointers protected SafeMemoryHandle(byte[] bytes) : base(IntPtr.Zero, true) @@ -284,8 +339,8 @@ namespace Vanara.InteropServices /// When overridden in a derived class, executes the code required to free the handle. /// - /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a - /// releaseHandleFailed MDA Managed Debugging Assistant. + /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it + /// generates a releaseHandleFailed MDA Managed Debugging Assistant. /// protected override bool ReleaseHandle() { @@ -307,8 +362,8 @@ namespace Vanara.InteropServices public abstract class SafeMemoryHandleExt : SafeMemoryHandle, ISafeMemoryHandle where TMem : IMemoryMethods, new() { /// - /// Maintains reference to other SafeMemoryHandleExt objects, the pointer to which are referred to by this object. This is to ensure that such objects - /// being referred to wouldn't be unreferenced until this object is active. + /// Maintains reference to other SafeMemoryHandleExt objects, the pointer to which are referred to by this object. This is to ensure + /// that such objects being referred to wouldn't be unreferenced until this object is active. /// private List references; @@ -323,12 +378,18 @@ namespace Vanara.InteropServices /// if set to true if this class is responsible for freeing the memory on disposal. protected SafeMemoryHandleExt(IntPtr handle, SizeT size, bool ownsHandle) : base(handle, size, ownsHandle) { } - /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native array equivalent. + /// + /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native + /// array equivalent. + /// /// Array of unmanaged pointers /// SafeHGlobalHandle object to an native (unmanaged) array of pointers protected SafeMemoryHandleExt(byte[] bytes) : base(bytes) { } - /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native array equivalent. + /// + /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native + /// array equivalent. + /// /// Array of unmanaged pointers /// SafeMemoryHandleExt object to an native (unmanaged) array of pointers protected SafeMemoryHandleExt(IntPtr[] values) : this(IntPtr.Size * values.Length) => Marshal.Copy(values, 0, handle, values.Length); @@ -344,8 +405,9 @@ namespace Vanara.InteropServices } /// - /// Adds reference to other SafeMemoryHandle objects, the pointer to which are referred to by this object. This is to ensure that such objects being - /// referred to wouldn't be unreferenced until this object is active. For e.g. when this object is an array of pointers to other objects + /// Adds reference to other SafeMemoryHandle objects, the pointer to which are referred to by this object. This is to ensure that + /// such objects being referred to wouldn't be unreferenced until this object is active. For e.g. when this object is an array of + /// pointers to other objects /// /// Collection of SafeMemoryHandle objects referred to by this object. public void AddSubReference(IEnumerable children) @@ -355,8 +417,9 @@ namespace Vanara.InteropServices references.AddRange(children); } - /// Extracts an array of structures of containing items. - /// This call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. + /// + /// Extracts an array of structures of containing items. This + /// call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. /// /// The type of the structures to retrieve. /// The number of structures to retrieve. @@ -372,8 +435,9 @@ namespace Vanara.InteropServices return handle.ToArray(count, prefixBytes, sz); } - /// Extracts an enumeration of structures of containing items. - /// This call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. + /// + /// Extracts an enumeration of structures of containing items. This call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures. /// /// The type of the structures to retrieve. /// The number of structures to retrieve. @@ -406,7 +470,10 @@ namespace Vanara.InteropServices return len == -1 ? str : str.Substring(0, len); } - /// Returns an enumeration of strings from memory where each string is pointed to by a preceding list of pointers of length . + /// + /// 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. @@ -414,15 +481,17 @@ namespace Vanara.InteropServices 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 - /// two '\0' characters. + /// 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 two '\0' characters. /// /// 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, sz); - /// Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter. + /// + /// 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. @@ -432,14 +501,16 @@ namespace Vanara.InteropServices 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. + /// 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 . + /// + /// 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."); @@ -458,7 +529,9 @@ namespace Vanara.InteropServices /// 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 . + /// + /// 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(in T value, bool autoExtend = true, int offset = 0) where T : struct { @@ -475,7 +548,9 @@ namespace Vanara.InteropServices /// Writes the specified value to an offset within this allocated memory. /// The value to write. - /// if set to true automatically extend the allocated memory to the size required to hold . + /// + /// 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(object value, bool autoExtend = true, int offset = 0) { @@ -493,8 +568,8 @@ namespace Vanara.InteropServices /// When overridden in a derived class, executes the code required to free the handle. /// - /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a - /// releaseHandleFailed MDA Managed Debugging Assistant. + /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it + /// generates a releaseHandleFailed MDA Managed Debugging Assistant. /// protected override bool ReleaseHandle() {