using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Vanara.Extensions;
namespace Vanara.PInvoke
{
/// Helper methods for structures.
public static class StructHelper
{
/// Gets the address of a reference.
/// The unmanaged value type to convert.
/// The target value.
/// The address of .
/// This address will only remain valid if the target value or its encapsulating type are pinned.
public static IntPtr DangerousAddressOf(ref T target) where T : unmanaged
{
unsafe
{
fixed (T* p = &target)
return (IntPtr)p;
}
}
/// Converts a field reference to array. Used when a structure defines an ANYSIZE array as the last field.
/// The unmanaged type to convert.
/// A reference to the field value.
/// The number of items in the array.
/// The offset from the field value at which to start extracting the array.
/// An item array of values of .
///
/// Properties defined with this can only be safely used when the structure has been marshaled via a dynamic memory block and not
/// when marshaled directly.
///
#if !(NET20 || NET35 || NET40)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public unsafe static T[] FieldToArray(ref T fieldReference, int count, int offset = 0) where T : unmanaged
{
if (count == 0) return new T[0];
return DangerousAddressOf(ref fieldReference).ToArray(count, offset);
}
/// Creates a new instance of with a size field set to the size of its unmanaged type.
/// The type to return .
///
/// Name of the field which is assigned the size. If , the first public or private field is used.
///
/// An initialized instance of .
public static T InitWithSize(string fieldName = null) where T : new()
{
const BindingFlags bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var fi = fieldName is null ? typeof(T).GetOrderedFields(bf).FirstOrDefault() : typeof(T).GetField(fieldName, bf);
var ret = (object)new T();
fi.SetValue(ret, Convert.ChangeType((uint)InteropExtensions.SizeOf(), fi.FieldType));
return (T)ret;
}
}
}