#if USE_NETCORE
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.IO;
using System.Runtime.CompilerServices;
using FlaxEngine.Assertions;
using FlaxEngine.Utilities;
using System.Runtime.InteropServices.Marshalling;
using FlaxEngine.Visject;
using System.Diagnostics;
using System.Collections;
using System.Buffers;
using System.Collections.Concurrent;
[assembly: DisableRuntimeMarshalling]
namespace FlaxEngine
{
#region Native structures
[StructLayout(LayoutKind.Sequential)]
internal struct NativeClassDefinitions
{
internal IntPtr typeHandle;
internal IntPtr name;
internal IntPtr fullname;
internal IntPtr @namespace;
internal uint typeAttributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeMethodDefinitions
{
internal IntPtr name;
internal int numParameters;
internal IntPtr typeHandle;
internal uint methodAttributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeFieldDefinitions
{
internal IntPtr name;
internal IntPtr fieldHandle;
internal IntPtr fieldTypeHandle;
internal uint fieldAttributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativePropertyDefinitions
{
internal IntPtr name;
internal IntPtr getterHandle;
internal IntPtr setterHandle;
internal uint getterFlags;
internal uint setterFlags;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeAttributeDefinitions
{
internal IntPtr name;
internal IntPtr attributeHandle;
internal IntPtr attributeTypeHandle;
}
[StructLayout(LayoutKind.Explicit)]
internal struct VariantNative
{
[StructLayout(LayoutKind.Sequential)]
internal struct VariantNativeType
{
internal VariantUtils.VariantType types;
internal IntPtr TypeName; // char*
}
[FieldOffset(0)]
VariantNativeType Type;
[FieldOffset(8)]
byte AsBool;
[FieldOffset(8)]
short AsInt16;
[FieldOffset(8)]
ushort AsUint16;
[FieldOffset(8)]
int AsInt;
[FieldOffset(8)]
uint AsUint;
[FieldOffset(8)]
long AsInt64;
[FieldOffset(8)]
ulong AsUint64;
[FieldOffset(8)]
float AsFloat;
[FieldOffset(8)]
double AsDouble;
[FieldOffset(8)]
IntPtr AsPointer;
[FieldOffset(8)]
int AsData0;
[FieldOffset(12)]
int AsData1;
[FieldOffset(16)]
int AsData2;
[FieldOffset(20)]
int AsData3;
[FieldOffset(24)]
int AsData4;
[FieldOffset(28)]
int AsData5;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VersionNative
{
internal int _Major;
internal int _Minor;
internal int _Build;
internal int _Revision;
internal VersionNative(Version ver)
{
_Major = ver.Major;
_Minor = ver.Minor;
_Build = ver.Build;
_Revision = ver.Revision;
}
internal Version GetVersion()
{
return new Version(_Major, _Minor, _Build, _Revision);
}
}
#endregion
#region Wrappers
///
/// Wrapper for managed arrays which are passed to unmanaged code.
///
internal unsafe class ManagedArray
{
private GCHandle pinnedArrayHandle;
private IntPtr unmanagedData;
private int elementSize;
private int length;
internal static ManagedArray WrapNewArray(Array arr) => new ManagedArray(arr);
///
/// Returns an instance of ManagedArray from shared pool.
///
///
/// The resources must be released by calling FreePooled() instead of Free()-method.
///
internal static ManagedArray WrapPooledArray(Array arr)
{
ManagedArray managedArray = ManagedArrayPool.Get();
managedArray.WrapArray(arr);
return managedArray;
}
internal static ManagedArray AllocateNewArray(T* ptr, int length) where T : unmanaged => new ManagedArray(ptr, length, Unsafe.SizeOf());
internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, int elementSize) => new ManagedArray(ptr.ToPointer(), length, elementSize);
///
/// Returns an instance of ManagedArray from shared pool.
///
///
/// The resources must be released by calling FreePooled() instead of Free()-method.
///
internal static ManagedArray AllocatePooledArray(T* ptr, int length) where T : unmanaged
{
ManagedArray managedArray = ManagedArrayPool.Get();
managedArray.Allocate(ptr, length);
return managedArray;
}
internal ManagedArray(Array arr) => WrapArray(arr);
internal void WrapArray(Array arr)
{
pinnedArrayHandle = GCHandle.Alloc(arr, GCHandleType.Pinned);
unmanagedData = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0);
length = arr.Length;
elementSize = Marshal.SizeOf(arr.GetType().GetElementType());
}
internal void Allocate(T* ptr, int length) where T : unmanaged
{
unmanagedData = new IntPtr(ptr);
this.length = length;
elementSize = Unsafe.SizeOf();
}
internal void Allocate(IntPtr ptr, int length, int elementSize)
{
unmanagedData = ptr;
this.length = length;
this.elementSize = elementSize;
}
private ManagedArray() { }
private ManagedArray(void* ptr, int length, int elementSize) => Allocate(new IntPtr(ptr), length, elementSize);
~ManagedArray()
{
if (unmanagedData != IntPtr.Zero)
Free();
}
internal void Free()
{
GC.SuppressFinalize(this);
if (pinnedArrayHandle.IsAllocated)
{
pinnedArrayHandle.Free();
unmanagedData = IntPtr.Zero;
}
if (unmanagedData != IntPtr.Zero)
{
Marshal.FreeHGlobal(unmanagedData);
unmanagedData = IntPtr.Zero;
}
}
internal void FreePooled()
{
Free();
ManagedArrayPool.Put(this);
}
internal IntPtr GetPointer => unmanagedData;
internal int Length => length;
internal int ElementSize => elementSize;
internal Span GetSpan() where T : struct => new Span(unmanagedData.ToPointer(), length);
internal T[] GetArray() where T : struct => new Span(unmanagedData.ToPointer(), length).ToArray();
///
/// Provides a pool of pre-allocated ManagedArray that can be re-used.
///
private static class ManagedArrayPool
{
private static List> pool = new List>();
internal static ManagedArray Get()
{
for (int i = 0; i < pool.Count; i++)
{
if (!pool[i].Item1)
{
var tuple = pool[i];
tuple.Item1 = true;
pool[i] = tuple;
return tuple.Item2;
}
}
var newTuple = (true, new ManagedArray());
pool.Add(newTuple);
return newTuple.Item2;
}
internal static void Put(ManagedArray obj)
{
for (int i = 0; i < pool.Count; i++)
{
if (pool[i].Item2 == obj)
{
var tuple = pool[i];
tuple.Item1 = false;
pool[i] = tuple;
return;
}
}
throw new Exception("Tried to free non-pooled ManagedArray as pooled ManagedArray");
}
}
}
internal static class ManagedString
{
internal static GCHandle EmptyStringHandle = GCHandle.Alloc(string.Empty);
[System.Diagnostics.DebuggerStepThrough]
internal static unsafe IntPtr ToNative(string str)
{
if (str == null)
return IntPtr.Zero;
else if (str == string.Empty)
return GCHandle.ToIntPtr(EmptyStringHandle);
Assert.IsTrue(str.Length > 0);
return GCHandle.ToIntPtr(GCHandle.Alloc(str, GCHandleType.Weak));
}
[System.Diagnostics.DebuggerStepThrough]
internal static string ToManaged(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
return Unsafe.As(GCHandle.FromIntPtr(ptr).Target);
}
[System.Diagnostics.DebuggerStepThrough]
internal static void Free(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return;
GCHandle handle = GCHandle.FromIntPtr(ptr);
if (handle == EmptyStringHandle)
return;
handle.Free();
}
}
#endregion
#region Marshallers
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(GCHandleMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(GCHandleMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(GCHandleMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(GCHandleMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(GCHandleMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(object), MarshalMode.ElementOut, typeof(GCHandleMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedRef, typeof(GCHandleMarshaller.Bidirectional))]
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(GCHandleMarshaller.Bidirectional))]
[CustomMarshaller(typeof(object), MarshalMode.ElementRef, typeof(GCHandleMarshaller))]
internal static class GCHandleMarshaller
{
public static class NativeToManaged
{
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : GCHandle.FromIntPtr(unmanaged).Target;
public static void Free(IntPtr unmanaged)
{
// This is a permanent handle, do not release it
}
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
if (unmanaged == IntPtr.Zero)
return;
GCHandle.FromIntPtr(unmanaged).Free();
}
}
public struct Bidirectional
{
object managed;
IntPtr unmanaged;
public void FromManaged(object managed) { this.managed = managed; }
public IntPtr ToUnmanaged() { unmanaged = GCHandleMarshaller.ToNative(managed); return unmanaged; }
public void FromUnmanaged(IntPtr unmanaged) { this.unmanaged = unmanaged; }
public object ToManaged() { managed = GCHandleMarshaller.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; }
public void Free()
{
// FIXME, might be a permanent handle or a temporary one
throw new NotImplementedException();
/*if (unmanaged == IntPtr.Zero)
return;
GCHandle.FromIntPtr(unmanaged).Free();*/
}
}
internal static object ConvertToManaged(IntPtr unmanaged) => ToManaged(unmanaged);
internal static IntPtr ConvertToUnmanaged(object managed) => ToNative(managed);
internal static object ToManaged(IntPtr managed) => managed != IntPtr.Zero ? GCHandle.FromIntPtr(managed).Target : null;
internal static IntPtr ToNative(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
internal static void Free(IntPtr unmanaged)
{
if (unmanaged == IntPtr.Zero)
return;
GCHandle.FromIntPtr(unmanaged).Free();
}
}
[CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))]
internal static class SystemTypeMarshaller
{
internal static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged));
internal static IntPtr ConvertToUnmanaged(Type managed)
{
if (managed == null)
return IntPtr.Zero;
GCHandle handle = NativeInterop.GetOrAddTypeGCHandle(managed);
return GCHandle.ToIntPtr(handle);
}
internal static void Free(IntPtr unmanaged)
{
// Cached handle, do not release
}
}
[CustomMarshaller(typeof(Exception), MarshalMode.Default, typeof(ExceptionMarshaller))]
internal static class ExceptionMarshaller
{
internal static Exception ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged));
internal static IntPtr ConvertToUnmanaged(Exception managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);
internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);
}
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller.NativeToManaged))]
internal static class ObjectMarshaller
{
public static class NativeToManaged
{
public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(GCHandle.FromIntPtr(unmanaged).Target) : null;
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
}
}
[CustomMarshaller(typeof(CultureInfo), MarshalMode.Default, typeof(CultureInfoMarshaller))]
internal static class CultureInfoMarshaller
{
internal static CultureInfo ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged));
internal static IntPtr ConvertToUnmanaged(CultureInfo managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);
internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);
}
[CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedIn, typeof(SystemArrayMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedOut, typeof(SystemArrayMarshaller.ManagedToNative))]
internal static class SystemArrayMarshaller
{
public struct ManagedToNative
{
ManagedArray managedArray;
GCHandle handle;
public void FromManaged(Array managed)
{
if (managed != null)
managedArray = ManagedArray.WrapPooledArray(managed);
}
public IntPtr ToUnmanaged()
{
if (managedArray == null)
return IntPtr.Zero;
handle = GCHandle.Alloc(managedArray);
return GCHandle.ToIntPtr(handle);
}
public void Free()
{
if (managedArray != null)
{
managedArray.FreePooled();
handle.Free();
}
}
}
}
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedIn, typeof(DictionaryMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.UnmanagedToManagedOut, typeof(DictionaryMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ElementIn, typeof(DictionaryMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedOut, typeof(DictionaryMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.UnmanagedToManagedIn, typeof(DictionaryMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ElementOut, typeof(DictionaryMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedRef, typeof(DictionaryMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.UnmanagedToManagedRef, typeof(DictionaryMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ElementRef, typeof(DictionaryMarshaller<,>))]
internal static unsafe class DictionaryMarshaller
{
public static class NativeToManaged
{
public static Dictionary ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller.ToManaged(unmanaged);
public static void Free(IntPtr unmanaged) => DictionaryMarshaller.Free(unmanaged);
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(Dictionary managed) => DictionaryMarshaller.ToNative(managed);
public static void Free(IntPtr unmanaged) => DictionaryMarshaller.Free(unmanaged);
}
public struct Bidirectional
{
Dictionary managed;
IntPtr unmanaged;
public void FromManaged(Dictionary managed) => this.managed = managed;
public IntPtr ToUnmanaged()
{
unmanaged = DictionaryMarshaller.ToNative(managed);
return unmanaged;
}
public void FromUnmanaged(IntPtr unmanaged) => this.unmanaged = unmanaged;
public Dictionary ToManaged()
{
managed = DictionaryMarshaller.ToManaged(unmanaged);
unmanaged = IntPtr.Zero;
return managed;
}
public void Free() => DictionaryMarshaller.Free(unmanaged);
}
public static Dictionary ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As>(GCHandle.FromIntPtr(unmanaged).Target) : null;
public static IntPtr ConvertToUnmanaged(Dictionary managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
public static Dictionary ToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As>(GCHandle.FromIntPtr(unmanaged).Target) : null;
public static IntPtr ToNative(Dictionary managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
if (unmanaged != IntPtr.Zero)
GCHandle.FromIntPtr(unmanaged).Free();
}
}
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(ArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(ArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(ArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(ArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(ArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(ArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(ArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(ArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(ArrayMarshaller<,>))]
[ContiguousCollectionMarshaller]
internal static unsafe class ArrayMarshaller where TUnmanagedElement : unmanaged
{
public static class NativeToManaged
{
internal static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements)
{
if (unmanaged is null)
return null;
return new T[numElements];
}
internal static Span GetManagedValuesDestination(T[]? managed) => managed;
internal static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements)
{
if (unmanaged == null)
return ReadOnlySpan.Empty;
ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
return managedArray.GetSpan();
}
internal static void Free(TUnmanagedElement* unmanaged)
{
if (unmanaged == null)
return;
GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged));
(Unsafe.As(handle.Target)).Free();
handle.Free();
}
internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
{
if (unmanaged == null)
return Span.Empty;
ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
return managedArray.GetSpan();
}
}
public static class ManagedToNative
{
internal static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
{
if (managed is null)
{
numElements = 0;
return null;
}
numElements = managed.Length;
ManagedArray managedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length);
var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray));
return (TUnmanagedElement*)ptr;
}
internal static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed;
internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
{
if (unmanaged == null)
return Span.Empty;
ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
return managedArray.GetSpan();
}
internal static void Free(TUnmanagedElement* unmanaged)
{
if (unmanaged == null)
return;
GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged));
(Unsafe.As(handle.Target)).FreePooled();
handle.Free();
}
}
public struct Bidirectional
{
T[] managedArray;
ManagedArray unmanagedArray;
GCHandle handle;
public void FromManaged(T[]? managed)
{
if (managed == null)
return;
managedArray = managed;
unmanagedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length);
handle = GCHandle.Alloc(unmanagedArray);
}
public ReadOnlySpan GetManagedValuesSource() => managedArray;
public Span GetUnmanagedValuesDestination()
{
if (unmanagedArray == null)
return Span.Empty;
return unmanagedArray.GetSpan();
}
public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)GCHandle.ToIntPtr(handle);
public void FromUnmanaged(TUnmanagedElement* unmanaged)
{
ManagedArray arr = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
if (managedArray == null || managedArray.Length != arr.Length)
managedArray = new T[arr.Length];
}
public ReadOnlySpan GetUnmanagedValuesSource(int numElements)
{
if (unmanagedArray == null)
return ReadOnlySpan.Empty;
return unmanagedArray.GetSpan();
}
public Span GetManagedValuesDestination(int numElements) => managedArray;
public T[] ToManaged() => managedArray;
public void Free()
{
unmanagedArray.FreePooled();
handle.Free();
}
}
internal static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
{
if (managed is null)
{
numElements = 0;
return null;
}
numElements = managed.Length;
ManagedArray managedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length);
IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray));
return (TUnmanagedElement*)handle;
}
internal static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed;
internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
{
if (unmanaged == null)
return Span.Empty;
ManagedArray unmanagedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
return unmanagedArray.GetSpan();
}
internal static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements];
internal static Span GetManagedValuesDestination(T[]? managed) => managed;
internal static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements)
{
if (unmanaged == null)
return ReadOnlySpan.Empty;
ManagedArray array = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
return array.GetSpan();
}
internal static void Free(TUnmanagedElement* unmanaged)
{
if (unmanaged == null)
return;
GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged));
Unsafe.As(handle.Target).FreePooled();
handle.Free();
}
}
[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(StringMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(StringMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedRef, typeof(StringMarshaller.Bidirectional))]
[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedRef, typeof(StringMarshaller.Bidirectional))]
[CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringMarshaller))]
internal static class StringMarshaller
{
public static class NativeToManaged
{
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
}
public static class ManagedToNative
{
public static unsafe IntPtr ConvertToUnmanaged(string managed)
{
if (managed == null)
return IntPtr.Zero;
return GCHandle.ToIntPtr(GCHandle.Alloc(managed, GCHandleType.Weak));
}
public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
}
public struct Bidirectional
{
string managed;
IntPtr unmanaged;
public void FromManaged(string managed) => this.managed = managed;
public IntPtr ToUnmanaged()
{
unmanaged = ManagedString.ToNative(managed);
return unmanaged;
}
public void FromUnmanaged(IntPtr unmanaged) => this.unmanaged = unmanaged;
public string ToManaged()
{
managed = ManagedString.ToManaged(unmanaged);
unmanaged = IntPtr.Zero;
return managed;
}
public void Free() => ManagedString.Free(unmanaged);
}
internal static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
internal static IntPtr ConvertToUnmanaged(string managed) => ManagedString.ToNative(managed);
internal static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
internal static string ToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
internal static IntPtr ToNative(string managed) => ManagedString.ToNative(managed);
}
#endregion
///
/// Provides a Mono-like API for native code to access managed runtime.
///
internal unsafe static partial class NativeInterop
{
///
/// Enables first-chance exception handling in invoked methods while debugger is attached.
///
public static bool CatchExceptions = true;
internal static Dictionary AssemblyLocations = new Dictionary();
private static bool firstAssemblyLoaded = false;
private static Dictionary typeCache = new Dictionary();
private static IntPtr boolTruePtr = GCHandle.ToIntPtr(GCHandle.Alloc((int)1, GCHandleType.Pinned));
private static IntPtr boolFalsePtr = GCHandle.ToIntPtr(GCHandle.Alloc((int)0, GCHandleType.Pinned));
private static List methodHandles = new();
private static List methodHandlesCollectible = new();
private static ConcurrentDictionary cachedDelegates = new ConcurrentDictionary();
private static ConcurrentDictionary cachedDelegatesCollectible = new ConcurrentDictionary();
private static Dictionary typeHandleCache = new Dictionary();
private static Dictionary typeHandleCacheCollectible = new Dictionary();
private static List fieldHandleCache = new();
private static List fieldHandleCacheCollectible = new();
private static Dictionary