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;
}
}