AirScout/AeroWizard/AeroWizard/Native/SafeHGlobalHandle.cs

206 wiersze
7.5 KiB
C#

using System.Collections.Generic;
using System.Diagnostics;
namespace System.Runtime.InteropServices
{
internal class SafeHGlobalHandle : SafeHandle
{
/// <summary>
/// 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.
/// </summary>
List<SafeHGlobalHandle> 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);
}
/// <summary>
/// Allocates from unmanaged memory to represent an array of pointers
/// and marshals the unmanaged pointers (IntPtr) to the native array
/// equivalent.
/// </summary>
/// <param name="values">Array of unmanaged pointers</param>
/// <returns>SafeHGlobalHandle object to an native (unmanaged) array of pointers</returns>
public SafeHGlobalHandle(IntPtr[] values) : this(IntPtr.Size * values.Length)
{
Marshal.Copy(values, 0, handle, values.Length);
}
/// <summary>
/// Allocates from unmanaged memory to represent a Unicode string (WSTR)
/// and marshal this to a native PWSTR.
/// </summary>
/// <param name="s">String</param>
/// <returns>SafeHGlobalHandle object to an native (unmanaged) Unicode string</returns>
public SafeHGlobalHandle(string s) : this(s == null ? IntPtr.Zero : Marshal.StringToHGlobalUni(s), (s?.Length + 1) * 2 ?? 0)
{
}
/*
/// <summary>
/// Initializes a new instance of the <see cref="SafeHGlobalHandle"/> class.
/// </summary>
/// <param name="s">The secure string.</param>
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;
}
}
*/
/// <summary>
/// Allocates from unmanaged memory sufficient memory to hold an object of type T.
/// </summary>
/// <typeparam name="T">Native type</typeparam>
/// <returns>SafeHGlobalHandle object to an native (unmanaged) memory block the size of T.</returns>
public static SafeHGlobalHandle AllocHGlobal<T>() => new SafeHGlobalHandle(Marshal.SizeOf(typeof(T)));
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Native structure type</typeparam>
/// <param name="values">Collection of structure objects</param>
/// <returns>SafeHGlobalHandle object to an native (unmanaged) array of structures</returns>
public static SafeHGlobalHandle AllocHGlobal<T>(ICollection<T> values) where T : struct
{
Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential);
return AllocHGlobal(0, values, values.Count);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Type of the trailing array of structures</typeparam>
/// <param name="prefixBytes">Number of bytes preceding the trailing array of structures</param>
/// <param name="values">Collection of structure objects</param>
/// <param name="count">Number of items in <paramref name="values"/>.</param>
/// <returns>SafeHGlobalHandle object to an native (unmanaged) structure with a trail array of structures</returns>
public static SafeHGlobalHandle AllocHGlobal<T>(int prefixBytes, IEnumerable<T> 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;
}
/// <summary>
/// Allocates from unmanaged memory to hold a copy of a structure.
/// </summary>
/// <typeparam name="T">Type of the structure.</typeparam>
/// <param name="obj">The object.</param>
/// <returns>SafeHGlobalHandle object to an native (unmanaged) structure</returns>
public static SafeHGlobalHandle AllocHGlobalStruct<T>(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;
}
/// <summary>
/// Gets the size of the allocated memory block.
/// </summary>
/// <value>
/// The sizeof the allocated memory block.
/// </value>
public int Size { get; }
/// <summary>
/// Allows to assign IntPtr to SafeHGlobalHandle
/// </summary>
public static implicit operator SafeHGlobalHandle(IntPtr ptr) => new SafeHGlobalHandle(ptr, 0, true);
/// <summary>
/// Allows to use SafeHGlobalHandle as IntPtr
/// </summary>
public static implicit operator IntPtr(SafeHGlobalHandle h) => h.DangerousGetHandle();
/// <summary>
/// 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
/// </summary>
/// <param name="children">Collection of SafeHGlobalHandle objects referred to by this object.</param>
public void AddSubReference(IEnumerable<SafeHGlobalHandle> children)
{
if (references == null)
references = new List<SafeHGlobalHandle>();
references.AddRange(children);
}
public T ToStructure<T>() 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<T>();
}
public T[] ToArray<T>(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<T>(count, prefixBytes);
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
Marshal.FreeHGlobal(handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
}
}