using System.Collections.Generic; using System.Diagnostics; namespace System.Runtime.InteropServices { internal class SafeHGlobalHandle : SafeHandle { /// /// Maintains reference to other SafeHGlobalHandle 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. /// List references; public SafeHGlobalHandle() : this(IntPtr.Zero, 0, false) { } public SafeHGlobalHandle(IntPtr handle, int size, bool ownsHandle = true) : base(IntPtr.Zero, ownsHandle) { if (handle != IntPtr.Zero) SetHandle(handle); Size = size; } public SafeHGlobalHandle(int size) : this() { if (size < 0) throw new ArgumentOutOfRangeException(nameof(size), "The value of this argument must be non-negative"); System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); SetHandle(Marshal.AllocHGlobal(size)); Size = size; } public SafeHGlobalHandle(object value) : this(Marshal.SizeOf(value)) { Marshal.StructureToPtr(value, handle, false); } /// /// 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) : this(IntPtr.Size * values.Length) { Marshal.Copy(values, 0, handle, values.Length); } /// /// Allocates from unmanaged memory to represent a Unicode string (WSTR) /// and marshal this to a native PWSTR. /// /// String /// SafeHGlobalHandle object to an native (unmanaged) Unicode string public SafeHGlobalHandle(string s) : this(s == null ? IntPtr.Zero : Marshal.StringToHGlobalUni(s), (s?.Length + 1) * 2 ?? 0) { } /* /// /// Initializes a new instance of the class. /// /// The secure string. public SafeHGlobalHandle(Security.SecureString s) : base(IntPtr.Zero, p => { Marshal.ZeroFreeGlobalAllocUnicode(p); return true; }, true) { if (s != null) { s.MakeReadOnly(); SetHandle(Marshal.SecureStringToGlobalAllocUnicode(s)); Size = s.Length; } } */ /// /// Allocates from unmanaged memory sufficient memory to hold an object of type T. /// /// Native type /// SafeHGlobalHandle object to an native (unmanaged) memory block the size of T. public static SafeHGlobalHandle AllocHGlobal() => new SafeHGlobalHandle(Marshal.SizeOf(typeof(T))); /// /// Allocates from unmanaged memory to represent an array of structures /// and marshals the structure elements to the native array of /// structures. ONLY structures with attribute StructLayout of /// LayoutKind.Sequential are supported. /// /// Native structure type /// Collection of structure objects /// SafeHGlobalHandle object to an native (unmanaged) array of structures public static SafeHGlobalHandle AllocHGlobal(ICollection values) where T : struct { Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); return AllocHGlobal(0, values, values.Count); } /// /// 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 /// Number of bytes preceding the trailing array of structures /// Collection of structure objects /// Number of items in . /// SafeHGlobalHandle object to an native (unmanaged) structure with a trail array of structures public static SafeHGlobalHandle AllocHGlobal(int prefixBytes, IEnumerable values, int count) where T : struct { Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); var result = new SafeHGlobalHandle(prefixBytes + Marshal.SizeOf(typeof(T)) * count); var ptr = new IntPtr(result.handle.ToInt32() + prefixBytes); foreach (var value in values) { Marshal.StructureToPtr(value, ptr, false); ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(T))); } return result; } /// /// Allocates from unmanaged memory to hold a copy of a structure. /// /// Type of the structure. /// The object. /// SafeHGlobalHandle object to an native (unmanaged) structure public static SafeHGlobalHandle AllocHGlobalStruct(T obj) where T : struct { Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); var result = new SafeHGlobalHandle(Marshal.SizeOf(typeof(T))); Marshal.StructureToPtr(obj, result.handle, false); return result; } /// /// Gets the size of the allocated memory block. /// /// /// The sizeof the allocated memory block. /// public int Size { get; } /// /// Allows to assign IntPtr to SafeHGlobalHandle /// public static implicit operator SafeHGlobalHandle(IntPtr ptr) => new SafeHGlobalHandle(ptr, 0, true); /// /// Allows to use SafeHGlobalHandle as IntPtr /// public static implicit operator IntPtr(SafeHGlobalHandle h) => h.DangerousGetHandle(); /// /// Adds reference to other SafeHGlobalHandle 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 SafeHGlobalHandle objects referred to by this object. public void AddSubReference(IEnumerable children) { if (references == null) references = new List(); references.AddRange(children); } public T ToStructure() where T : struct { if (IsInvalid) return default(T); if (Size < Marshal.SizeOf(typeof(T))) throw new InsufficientMemoryException("Requested structure is larger than the memory allocated."); return handle.ToStructure(); } public T[] ToArray(int count, int prefixBytes = 0) where T : struct { if (IsInvalid) return null; if (Size < Marshal.SizeOf(typeof(T)) * count + prefixBytes) throw new InsufficientMemoryException("Requested array is larger than the memory allocated."); Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); return handle.ToArray(count, prefixBytes); } protected override bool ReleaseHandle() { if (!IsInvalid) Marshal.FreeHGlobal(handle); return true; } public override bool IsInvalid => handle == IntPtr.Zero; } }