using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Security; using Vanara.PInvoke; namespace Vanara.InteropServices; /// Unmanaged memory methods for HGlobal. /// public sealed class HGlobalMemoryMethods : IMemoryMethods { /// bool ISimpleMemoryMethods.AllocZeroes => false; /// Gets a value indicating whether this memory supports locking. /// if lockable; otherwise, . bool ISimpleMemoryMethods.Lockable => false; /// Static instance to methods. public static IMemoryMethods Instance { get; } = new HGlobalMemoryMethods(); /// Gets a handle to a memory allocation of the specified size. /// The size, in bytes, of memory to allocate. /// A memory handle. public IntPtr AllocMem(int size) => Marshal.AllocHGlobal(size); /// Gets the Ansi allocation method. /// The secure string. /// A memory handle. public IntPtr AllocSecureStringAnsi(SecureString? secureString) => secureString is null ? IntPtr.Zero : Marshal.SecureStringToGlobalAllocAnsi(secureString); /// Gets the Unicode allocation method. /// The secure string. /// A memory handle. public IntPtr AllocSecureStringUni(SecureString? secureString) => secureString is null ? IntPtr.Zero : Marshal.SecureStringToGlobalAllocUnicode(secureString); /// Gets the Ansi string allocation method. /// The value. /// A memory handle. public IntPtr AllocStringAnsi(string? value) => value is null ? IntPtr.Zero : Marshal.StringToHGlobalAnsi(value); /// Gets the Unicode string allocation method. /// The value. /// A memory handle. public IntPtr AllocStringUni(string? value) => value is null ? IntPtr.Zero : Marshal.StringToHGlobalUni(value); /// Frees the memory associated with a handle. /// A memory handle. public void FreeMem(IntPtr hMem) => Marshal.FreeHGlobal(hMem); /// Gets the Ansi free method. /// A memory handle. public void FreeSecureStringAnsi(IntPtr hMem) => Marshal.ZeroFreeGlobalAllocAnsi(hMem); /// Gets the Unicode free method. /// A memory handle. public void FreeSecureStringUni(IntPtr hMem) => Marshal.ZeroFreeGlobalAllocUnicode(hMem); /// Locks the memory of a specified handle and gets a pointer to it. /// A memory handle. /// A pointer to the locked memory. public IntPtr LockMem(IntPtr hMem) => hMem; /// Gets the reallocation method. /// A memory handle. /// The size, in bytes, of memory to allocate. /// A memory handle. public IntPtr ReAllocMem(IntPtr hMem, int size) => Marshal.ReAllocHGlobal(hMem, (IntPtr)size); /// Unlocks the memory of a specified handle. /// A memory handle. /// if the memory object is still locked after decrementing the lock count; otherwise . public bool UnlockMem(IntPtr hMem) => false; } /// A for memory allocated via LocalAlloc. /// public class SafeHGlobalHandle : SafeMemoryHandleExt { /// Initializes a new instance of the class. /// The handle. /// The size of memory allocated to the handle, in bytes. /// if set to true if this class is responsible for freeing the memory on disposal. public SafeHGlobalHandle(IntPtr handle, SizeT size, bool ownsHandle = true) : base(handle, size, ownsHandle) { } /// Initializes a new instance of the class. /// The handle. /// if set to true if this class is responsible for freeing the memory on disposal. public SafeHGlobalHandle(IntPtr handle, bool ownsHandle = true) : base(handle, GetPtrSize(handle), ownsHandle) { } /// Initializes a new instance of the class. /// The size of memory to allocate, in bytes. /// size - The value of this argument must be non-negative public SafeHGlobalHandle(SizeT size) : base(size) { } /// 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 public SafeHGlobalHandle(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. /// Array of unmanaged pointers /// SafeHGlobalHandle object to an native (unmanaged) array of pointers public SafeHGlobalHandle(IntPtr[] values) : base(values) { } /// Allocates from unmanaged memory to represent a Unicode string (WSTR) and marshal this to a native PWSTR. /// The string value. /// SafeHGlobalHandle object to an native (unmanaged) Unicode string public SafeHGlobalHandle(string s) : base(s) { } /// Initializes a new instance of the class. [ExcludeFromCodeCoverage] internal SafeHGlobalHandle() : base(0) { } /// Represents a NULL memory pointer. public static SafeHGlobalHandle Null { get; } = new SafeHGlobalHandle(IntPtr.Zero, 0, false); /// Converts an to a where it owns the reference. /// The . /// The result of the conversion. public static implicit operator SafeHGlobalHandle(IntPtr ptr) => new(ptr, 0, true); /// Allocates from unmanaged memory sufficient memory to hold an object of type T. /// Native type /// The value. /// object to an native (unmanaged) memory block the size of T. public static SafeHGlobalHandle CreateFromStructure(in T? value = default) => new(InteropExtensions.MarshalToPtr(value, mm.AllocMem, out int s), s); /// /// Allocates from unmanaged memory to represent a structure with a variable length array at the end and marshal these structure elements. It is the /// callers responsibility to marshal what precedes the trailing array into the unmanaged memory. ONLY structures with attribute StructLayout of /// LayoutKind.Sequential are supported. /// /// Type of the trailing array of structures /// Collection of structure objects /// Number of items in . /// Number of bytes preceding the trailing array of structures /// object to an native (unmanaged) structure with a trail array of structures public static SafeHGlobalHandle CreateFromList(IEnumerable values, int count = -1, int prefixBytes = 0) => new(InteropExtensions.MarshalToPtr(count < 0 ? values : values.Take(count), mm.AllocMem, out int s, prefixBytes), s); /// Allocates from unmanaged memory sufficient memory to hold an array of strings. /// The list of strings. /// The packing type for the strings. /// The character set to use for the strings. /// Number of bytes preceding the trailing strings. /// object to an native (unmanaged) array of strings stored using the model and the character set defined by . public static SafeHGlobalHandle CreateFromStringList(IEnumerable values, StringListPackMethod packing = StringListPackMethod.Concatenated, CharSet charSet = CharSet.Auto, int prefixBytes = 0) => new(InteropExtensions.MarshalToPtr(values, packing, mm.AllocMem, out int s, charSet, prefixBytes), s); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern SizeT GlobalSize([In] IntPtr hMem); private static SizeT GetPtrSize(IntPtr hMem) { var sz = GlobalSize(hMem); if (sz == 0) { var err = Marshal.GetHRForLastWin32Error(); if (err != 0) Marshal.ThrowExceptionForHR(err); } return sz; } }