Refactor Native Interop codebase with cleanup/rename
This commit is contained in:
@@ -11,7 +11,7 @@ using System.Diagnostics;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
internal unsafe static partial class NativeInterop
|
||||
unsafe partial class NativeInterop
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for invoking managed methods from delegates.
|
||||
489
Source/Engine/Engine/NativeInterop.Managed.cs
Normal file
489
Source/Engine/Engine/NativeInterop.Managed.cs
Normal file
@@ -0,0 +1,489 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_NETCORE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using FlaxEngine.Assertions;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
#pragma warning disable 1591
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper for managed arrays which are passed to unmanaged code.
|
||||
/// </summary>
|
||||
public unsafe class ManagedArray
|
||||
{
|
||||
private ManagedHandle _pinnedArrayHandle;
|
||||
private IntPtr _unmanagedData;
|
||||
private Type _arrayType;
|
||||
private Type _elementType;
|
||||
private int _elementSize;
|
||||
private int _length;
|
||||
|
||||
public static ManagedArray WrapNewArray(Array arr) => new ManagedArray(arr, arr.GetType());
|
||||
|
||||
public static ManagedArray WrapNewArray(Array arr, Type arrayType) => new ManagedArray(arr, arrayType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of ManagedArray from shared pool.
|
||||
/// </summary>
|
||||
/// <remarks>The resources must be released by calling FreePooled() instead of Free()-method.</remarks>
|
||||
public static ManagedArray WrapPooledArray(Array arr)
|
||||
{
|
||||
ManagedArray managedArray = ManagedArrayPool.Get();
|
||||
managedArray.WrapArray(arr, arr.GetType());
|
||||
return managedArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of ManagedArray from shared pool.
|
||||
/// </summary>
|
||||
/// <remarks>The resources must be released by calling FreePooled() instead of Free()-method.</remarks>
|
||||
public static ManagedArray WrapPooledArray(Array arr, Type arrayType)
|
||||
{
|
||||
ManagedArray managedArray = ManagedArrayPool.Get();
|
||||
managedArray.WrapArray(arr, arrayType);
|
||||
return managedArray;
|
||||
}
|
||||
|
||||
internal static ManagedArray AllocateNewArray(int length, Type arrayType, Type elementType)
|
||||
=> new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, Marshal.SizeOf(elementType)), length, arrayType, elementType);
|
||||
|
||||
internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, Type arrayType, Type elementType)
|
||||
=> new ManagedArray(ptr, length, arrayType, elementType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of ManagedArray from shared pool.
|
||||
/// </summary>
|
||||
/// <remarks>The resources must be released by calling FreePooled() instead of Free()-method.</remarks>
|
||||
public static ManagedArray AllocatePooledArray<T>(T* ptr, int length) where T : unmanaged
|
||||
{
|
||||
ManagedArray managedArray = ManagedArrayPool.Get();
|
||||
managedArray.Allocate(ptr, length);
|
||||
return managedArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of ManagedArray from shared pool.
|
||||
/// </summary>
|
||||
/// <remarks>The resources must be released by calling FreePooled() instead of Free()-method.</remarks>
|
||||
public static ManagedArray AllocatePooledArray<T>(int length) where T : unmanaged
|
||||
{
|
||||
ManagedArray managedArray = ManagedArrayPool.Get();
|
||||
managedArray.Allocate((T*)NativeInterop.NativeAlloc(length, Unsafe.SizeOf<T>()), length);
|
||||
return managedArray;
|
||||
}
|
||||
|
||||
public ManagedArray(Array arr, Type elementType) => WrapArray(arr, elementType);
|
||||
|
||||
internal void WrapArray(Array arr, Type arrayType)
|
||||
{
|
||||
_pinnedArrayHandle = ManagedHandle.Alloc(arr, GCHandleType.Pinned);
|
||||
_unmanagedData = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0);
|
||||
_length = arr.Length;
|
||||
_arrayType = arrayType;
|
||||
_elementType = arr.GetType().GetElementType();
|
||||
_elementSize = Marshal.SizeOf(_elementType);
|
||||
}
|
||||
|
||||
internal void Allocate<T>(T* ptr, int length) where T : unmanaged
|
||||
{
|
||||
_unmanagedData = new IntPtr(ptr);
|
||||
_length = length;
|
||||
_arrayType = typeof(T).MakeArrayType();
|
||||
_elementType = typeof(T);
|
||||
_elementSize = Unsafe.SizeOf<T>();
|
||||
}
|
||||
|
||||
private ManagedArray()
|
||||
{
|
||||
}
|
||||
|
||||
private ManagedArray(IntPtr ptr, int length, Type arrayType, Type elementType)
|
||||
{
|
||||
Assert.IsTrue(arrayType.IsArray);
|
||||
_unmanagedData = ptr;
|
||||
_length = length;
|
||||
_arrayType = arrayType;
|
||||
_elementType = elementType;
|
||||
_elementSize = Marshal.SizeOf(elementType);
|
||||
}
|
||||
|
||||
~ManagedArray()
|
||||
{
|
||||
if (_unmanagedData != IntPtr.Zero)
|
||||
Free();
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
if (_pinnedArrayHandle.IsAllocated)
|
||||
{
|
||||
_pinnedArrayHandle.Free();
|
||||
_unmanagedData = IntPtr.Zero;
|
||||
}
|
||||
if (_unmanagedData != IntPtr.Zero)
|
||||
{
|
||||
NativeInterop.NativeFree(_unmanagedData.ToPointer());
|
||||
_unmanagedData = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void FreePooled()
|
||||
{
|
||||
Free();
|
||||
ManagedArrayPool.Put(this);
|
||||
}
|
||||
|
||||
internal IntPtr Pointer => _unmanagedData;
|
||||
|
||||
internal int Length => _length;
|
||||
|
||||
internal int ElementSize => _elementSize;
|
||||
|
||||
internal Type ElementType => _elementType;
|
||||
|
||||
internal Type ArrayType => _arrayType;
|
||||
|
||||
public Span<T> ToSpan<T>() where T : struct => new Span<T>(_unmanagedData.ToPointer(), _length);
|
||||
|
||||
public T[] ToArray<T>() where T : struct => new Span<T>(_unmanagedData.ToPointer(), _length).ToArray();
|
||||
|
||||
public Array ToArray() => ArrayCast.ToArray(new Span<byte>(_unmanagedData.ToPointer(), _length * _elementSize), _elementType);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an Array of the specified type from span of bytes.
|
||||
/// </summary>
|
||||
private static class ArrayCast
|
||||
{
|
||||
delegate Array GetDelegate(Span<byte> span);
|
||||
|
||||
[ThreadStatic]
|
||||
private static Dictionary<Type, GetDelegate> delegates;
|
||||
|
||||
internal static Array ToArray(Span<byte> span, Type type)
|
||||
{
|
||||
if (delegates == null)
|
||||
delegates = new();
|
||||
if (!delegates.TryGetValue(type, out var deleg))
|
||||
{
|
||||
deleg = typeof(ArrayCastInternal<>).MakeGenericType(type).GetMethod(nameof(ArrayCastInternal<int>.ToArray), BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate<GetDelegate>();
|
||||
delegates.Add(type, deleg);
|
||||
}
|
||||
return deleg(span);
|
||||
}
|
||||
|
||||
private static class ArrayCastInternal<T> where T : struct
|
||||
{
|
||||
internal static Array ToArray(Span<byte> span)
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(span).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a pool of pre-allocated ManagedArray that can be re-used.
|
||||
/// </summary>
|
||||
private static class ManagedArrayPool
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static List<ValueTuple<bool, ManagedArray>> pool;
|
||||
|
||||
internal static ManagedArray Get()
|
||||
{
|
||||
if (pool == null)
|
||||
pool = new List<ValueTuple<bool, ManagedArray>>();
|
||||
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 ManagedHandle EmptyStringHandle = ManagedHandle.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 ManagedHandle.ToIntPtr(EmptyStringHandle);
|
||||
Assert.IsTrue(str.Length > 0);
|
||||
return ManagedHandle.ToIntPtr(str);
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static unsafe IntPtr ToNativeWeak(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return IntPtr.Zero;
|
||||
else if (str == string.Empty)
|
||||
return ManagedHandle.ToIntPtr(EmptyStringHandle);
|
||||
Assert.IsTrue(str.Length > 0);
|
||||
return ManagedHandle.ToIntPtr(str, GCHandleType.Weak);
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static string ToManaged(IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
return null;
|
||||
return Unsafe.As<string>(ManagedHandle.FromIntPtr(ptr).Target);
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static void Free(IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
return;
|
||||
ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
|
||||
if (handle == EmptyStringHandle)
|
||||
return;
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle to managed objects which can be stored in native code.
|
||||
/// </summary>
|
||||
public struct ManagedHandle
|
||||
{
|
||||
private IntPtr handle;
|
||||
|
||||
private ManagedHandle(IntPtr handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
private ManagedHandle(object value, GCHandleType type)
|
||||
{
|
||||
handle = ManagedHandlePool.AllocateHandle(value, type);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ManagedHandle Alloc(object value) => new ManagedHandle(value, GCHandleType.Normal);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ManagedHandle Alloc(object value, GCHandleType type) => new ManagedHandle(value, type);
|
||||
|
||||
public void Free()
|
||||
{
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
ManagedHandlePool.FreeHandle(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
ManagedHandlePool.TryCollectWeakHandles();
|
||||
}
|
||||
|
||||
public object Target
|
||||
{
|
||||
get => ManagedHandlePool.GetObject(handle);
|
||||
set => ManagedHandlePool.SetObject(handle, value);
|
||||
}
|
||||
|
||||
public bool IsAllocated => handle != IntPtr.Zero;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator ManagedHandle(IntPtr value) => FromIntPtr(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ManagedHandle FromIntPtr(IntPtr value) => new ManagedHandle(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator IntPtr(ManagedHandle value) => ToIntPtr(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IntPtr ToIntPtr(object value) => ManagedHandlePool.AllocateHandle(value, GCHandleType.Normal);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IntPtr ToIntPtr(object value, GCHandleType type) => ManagedHandlePool.AllocateHandle(value, type);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IntPtr ToIntPtr(ManagedHandle value) => value.handle;
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override bool Equals(object o) => o is ManagedHandle other && Equals(other);
|
||||
|
||||
public bool Equals(ManagedHandle other) => handle == other.handle;
|
||||
|
||||
public static bool operator ==(ManagedHandle a, ManagedHandle b) => a.handle == b.handle;
|
||||
|
||||
public static bool operator !=(ManagedHandle a, ManagedHandle b) => a.handle != b.handle;
|
||||
|
||||
private static class ManagedHandlePool
|
||||
{
|
||||
private static ulong normalHandleAccumulator = 0;
|
||||
private static ulong pinnedHandleAccumulator = 0;
|
||||
private static ulong weakHandleAccumulator = 0;
|
||||
|
||||
private static object poolLock = new object();
|
||||
private static Dictionary<IntPtr, object> persistentPool = new Dictionary<nint, object>();
|
||||
private static Dictionary<IntPtr, GCHandle> pinnedPool = new Dictionary<nint, GCHandle>();
|
||||
|
||||
private static Dictionary<IntPtr, object> weakPool1 = new Dictionary<nint, object>();
|
||||
private static Dictionary<IntPtr, object> weakPool2 = new Dictionary<nint, object>();
|
||||
private static Dictionary<IntPtr, object> weakPool = weakPool1;
|
||||
private static Dictionary<IntPtr, object> weakPoolOther = weakPool2;
|
||||
|
||||
private static int nextCollection = GC.CollectionCount(0) + 1;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to free all references to old weak handles so GC can collect them.
|
||||
/// </summary>
|
||||
internal static void TryCollectWeakHandles()
|
||||
{
|
||||
if (GC.CollectionCount(0) < nextCollection)
|
||||
return;
|
||||
|
||||
lock (poolLock)
|
||||
{
|
||||
nextCollection = GC.CollectionCount(0) + 1;
|
||||
|
||||
var swap = weakPoolOther;
|
||||
weakPoolOther = weakPool;
|
||||
weakPool = swap;
|
||||
|
||||
weakPool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr NewHandle(GCHandleType type)
|
||||
{
|
||||
IntPtr handle;
|
||||
if (type == GCHandleType.Normal)
|
||||
handle = (IntPtr)Interlocked.Increment(ref normalHandleAccumulator);
|
||||
else if (type == GCHandleType.Pinned)
|
||||
handle = (IntPtr)Interlocked.Increment(ref pinnedHandleAccumulator);
|
||||
else //if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
|
||||
handle = (IntPtr)Interlocked.Increment(ref weakHandleAccumulator);
|
||||
|
||||
// Two bits reserved for the type
|
||||
handle |= (IntPtr)(((ulong)type << 62) & 0xC000000000000000);
|
||||
return handle;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static GCHandleType GetHandleType(IntPtr handle)
|
||||
{
|
||||
return (GCHandleType)(((ulong)handle & 0xC000000000000000) >> 62);
|
||||
}
|
||||
|
||||
internal static IntPtr AllocateHandle(object value, GCHandleType type)
|
||||
{
|
||||
IntPtr handle = NewHandle(type);
|
||||
lock (poolLock)
|
||||
{
|
||||
if (type == GCHandleType.Normal)
|
||||
persistentPool.Add(handle, value);
|
||||
else if (type == GCHandleType.Pinned)
|
||||
pinnedPool.Add(handle, GCHandle.Alloc(value, GCHandleType.Pinned));
|
||||
else if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
|
||||
weakPool.Add(handle, value);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal static object GetObject(IntPtr handle)
|
||||
{
|
||||
object value;
|
||||
GCHandleType type = GetHandleType(handle);
|
||||
lock (poolLock)
|
||||
{
|
||||
if (type == GCHandleType.Normal && persistentPool.TryGetValue(handle, out value))
|
||||
return value;
|
||||
else if (type == GCHandleType.Pinned && pinnedPool.TryGetValue(handle, out GCHandle gchandle))
|
||||
return gchandle.Target;
|
||||
else if (weakPool.TryGetValue(handle, out value))
|
||||
return value;
|
||||
else if (weakPoolOther.TryGetValue(handle, out value))
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new Exception("Invalid ManagedHandle");
|
||||
}
|
||||
|
||||
internal static void SetObject(IntPtr handle, object value)
|
||||
{
|
||||
GCHandleType type = GetHandleType(handle);
|
||||
lock (poolLock)
|
||||
{
|
||||
if (type == GCHandleType.Normal && persistentPool.ContainsKey(handle))
|
||||
persistentPool[handle] = value;
|
||||
else if (type == GCHandleType.Pinned && pinnedPool.TryGetValue(handle, out GCHandle gchandle))
|
||||
gchandle.Target = value;
|
||||
else if (weakPool.ContainsKey(handle))
|
||||
weakPool[handle] = value;
|
||||
else if (weakPoolOther.ContainsKey(handle))
|
||||
weakPoolOther[handle] = value;
|
||||
else
|
||||
throw new Exception("Invalid ManagedHandle");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void FreeHandle(IntPtr handle)
|
||||
{
|
||||
GCHandleType type = GetHandleType(handle);
|
||||
lock (poolLock)
|
||||
{
|
||||
if (type == GCHandleType.Normal && persistentPool.Remove(handle))
|
||||
return;
|
||||
else if (type == GCHandleType.Pinned && pinnedPool.Remove(handle, out GCHandle gchandle))
|
||||
{
|
||||
gchandle.Free();
|
||||
return;
|
||||
}
|
||||
else if (weakPool.Remove(handle))
|
||||
return;
|
||||
else if (weakPoolOther.Remove(handle))
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception("Invalid ManagedHandle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
519
Source/Engine/Engine/NativeInterop.Marshallers.cs
Normal file
519
Source/Engine/Engine/NativeInterop.Marshallers.cs
Normal file
@@ -0,0 +1,519 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_NETCORE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
#pragma warning disable 1591
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
|
||||
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.ElementOut, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedRef, typeof(ManagedHandleMarshaller.Bidirectional))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(ManagedHandleMarshaller.Bidirectional))]
|
||||
[CustomMarshaller(typeof(object), MarshalMode.ElementRef, typeof(ManagedHandleMarshaller))]
|
||||
public static class ManagedHandleMarshaller
|
||||
{
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.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 ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
|
||||
public static void Free(IntPtr unmanaged)
|
||||
{
|
||||
if (unmanaged == IntPtr.Zero)
|
||||
return;
|
||||
ManagedHandle.FromIntPtr(unmanaged).Free();
|
||||
}
|
||||
}
|
||||
|
||||
public struct Bidirectional
|
||||
{
|
||||
object managed;
|
||||
IntPtr unmanaged;
|
||||
|
||||
public void FromManaged(object managed)
|
||||
{
|
||||
this.managed = managed;
|
||||
}
|
||||
|
||||
public IntPtr ToUnmanaged()
|
||||
{
|
||||
unmanaged = ManagedHandleMarshaller.ToNative(managed);
|
||||
return unmanaged;
|
||||
}
|
||||
|
||||
public void FromUnmanaged(IntPtr unmanaged)
|
||||
{
|
||||
this.unmanaged = unmanaged;
|
||||
}
|
||||
|
||||
public object ToManaged()
|
||||
{
|
||||
managed = ManagedHandleMarshaller.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;
|
||||
unmanaged.Free();*/
|
||||
}
|
||||
}
|
||||
|
||||
public static object ConvertToManaged(IntPtr unmanaged) => ToManaged(unmanaged);
|
||||
public static IntPtr ConvertToUnmanaged(object managed) => ToNative(managed);
|
||||
public static object ToManaged(IntPtr managed) => managed != IntPtr.Zero ? ManagedHandle.FromIntPtr(managed).Target : null;
|
||||
public static IntPtr ToNative(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
|
||||
public static void Free(IntPtr unmanaged)
|
||||
{
|
||||
if (unmanaged == IntPtr.Zero)
|
||||
return;
|
||||
ManagedHandle.FromIntPtr(unmanaged).Free();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))]
|
||||
public static class SystemTypeMarshaller
|
||||
{
|
||||
public static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As<Type>(ManagedHandleMarshaller.ConvertToManaged(unmanaged));
|
||||
|
||||
public static IntPtr ConvertToUnmanaged(Type managed)
|
||||
{
|
||||
if (managed == null)
|
||||
return IntPtr.Zero;
|
||||
ManagedHandle handle = NativeInterop.GetTypeGCHandle(managed);
|
||||
return ManagedHandle.ToIntPtr(handle);
|
||||
}
|
||||
|
||||
public static void Free(IntPtr unmanaged)
|
||||
{
|
||||
// Cached handle, do not release
|
||||
}
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(Exception), MarshalMode.Default, typeof(ExceptionMarshaller))]
|
||||
public static class ExceptionMarshaller
|
||||
{
|
||||
public static Exception ConvertToManaged(IntPtr unmanaged) => Unsafe.As<Exception>(ManagedHandleMarshaller.ConvertToManaged(unmanaged));
|
||||
public static IntPtr ConvertToUnmanaged(Exception managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed);
|
||||
public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.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))]
|
||||
public static class ObjectMarshaller
|
||||
{
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
|
||||
}
|
||||
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(CultureInfo), MarshalMode.Default, typeof(CultureInfoMarshaller))]
|
||||
public static class CultureInfoMarshaller
|
||||
{
|
||||
public static CultureInfo ConvertToManaged(IntPtr unmanaged) => Unsafe.As<CultureInfo>(ManagedHandleMarshaller.ConvertToManaged(unmanaged));
|
||||
public static IntPtr ConvertToUnmanaged(CultureInfo managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed);
|
||||
public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged);
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedIn, typeof(SystemArrayMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedOut, typeof(SystemArrayMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedOut, typeof(SystemArrayMarshaller.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedIn, typeof(SystemArrayMarshaller.NativeToManaged))]
|
||||
public static unsafe class SystemArrayMarshaller
|
||||
{
|
||||
public struct ManagedToNative
|
||||
{
|
||||
ManagedArray managedArray;
|
||||
ManagedHandle handle;
|
||||
|
||||
public void FromManaged(Array managed)
|
||||
{
|
||||
if (managed != null)
|
||||
managedArray = ManagedArray.WrapPooledArray(managed);
|
||||
}
|
||||
|
||||
public IntPtr ToUnmanaged()
|
||||
{
|
||||
if (managedArray == null)
|
||||
return IntPtr.Zero;
|
||||
handle = ManagedHandle.Alloc(managedArray);
|
||||
return ManagedHandle.ToIntPtr(handle);
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
if (managedArray == null)
|
||||
return;
|
||||
managedArray.FreePooled();
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public struct NativeToManaged
|
||||
{
|
||||
ManagedHandle handle;
|
||||
ManagedArray managedArray;
|
||||
|
||||
public void FromUnmanaged(IntPtr unmanaged)
|
||||
{
|
||||
if (unmanaged == IntPtr.Zero)
|
||||
return;
|
||||
handle = ManagedHandle.FromIntPtr(unmanaged);
|
||||
}
|
||||
|
||||
public Array ToManaged()
|
||||
{
|
||||
if (!handle.IsAllocated)
|
||||
return null;
|
||||
managedArray = Unsafe.As<ManagedArray>(handle.Target);
|
||||
return managedArray.ToArray();
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
if (!handle.IsAllocated)
|
||||
return;
|
||||
managedArray.Free();
|
||||
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<,>))]
|
||||
public static unsafe class DictionaryMarshaller<T, U>
|
||||
{
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
|
||||
public static void Free(IntPtr unmanaged) => DictionaryMarshaller<T, U>.Free(unmanaged);
|
||||
}
|
||||
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed);
|
||||
public static void Free(IntPtr unmanaged) => DictionaryMarshaller<T, U>.Free(unmanaged);
|
||||
}
|
||||
|
||||
public struct Bidirectional
|
||||
{
|
||||
Dictionary<T, U> managed;
|
||||
IntPtr unmanaged;
|
||||
|
||||
public void FromManaged(Dictionary<T, U> managed) => this.managed = managed;
|
||||
|
||||
public IntPtr ToUnmanaged()
|
||||
{
|
||||
unmanaged = DictionaryMarshaller<T, U>.ToNative(managed);
|
||||
return unmanaged;
|
||||
}
|
||||
|
||||
public void FromUnmanaged(IntPtr unmanaged) => this.unmanaged = unmanaged;
|
||||
|
||||
public Dictionary<T, U> ToManaged()
|
||||
{
|
||||
managed = DictionaryMarshaller<T, U>.ToManaged(unmanaged);
|
||||
unmanaged = IntPtr.Zero;
|
||||
return managed;
|
||||
}
|
||||
|
||||
public void Free() => DictionaryMarshaller<T, U>.Free(unmanaged);
|
||||
}
|
||||
|
||||
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<Dictionary<T, U>>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
|
||||
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
|
||||
public static Dictionary<T, U> ToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<Dictionary<T, U>>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
|
||||
public static IntPtr ToNative(Dictionary<T, U> managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
|
||||
public static void Free(IntPtr unmanaged)
|
||||
{
|
||||
if (unmanaged != IntPtr.Zero)
|
||||
ManagedHandle.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]
|
||||
public static unsafe class ArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
|
||||
{
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged is null)
|
||||
return null;
|
||||
return new T[numElements];
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[]? managed) => managed;
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return ReadOnlySpan<TUnmanagedElement>.Empty;
|
||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
return managedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public static void Free(TUnmanagedElement* unmanaged)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return;
|
||||
ManagedHandle handle = ManagedHandle.FromIntPtr(new IntPtr(unmanaged));
|
||||
(Unsafe.As<ManagedArray>(handle.Target)).Free();
|
||||
handle.Free();
|
||||
}
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return Span<TUnmanagedElement>.Empty;
|
||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
return managedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
|
||||
{
|
||||
if (managed is null)
|
||||
{
|
||||
numElements = 0;
|
||||
return null;
|
||||
}
|
||||
numElements = managed.Length;
|
||||
ManagedArray managedArray = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
|
||||
var ptr = ManagedHandle.ToIntPtr(managedArray);
|
||||
return (TUnmanagedElement*)ptr;
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[]? managed) => managed;
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return Span<TUnmanagedElement>.Empty;
|
||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
return managedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public static void Free(TUnmanagedElement* unmanaged)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return;
|
||||
ManagedHandle handle = ManagedHandle.FromIntPtr(new IntPtr(unmanaged));
|
||||
(Unsafe.As<ManagedArray>(handle.Target)).FreePooled();
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public struct Bidirectional
|
||||
{
|
||||
T[] managedArray;
|
||||
ManagedArray unmanagedArray;
|
||||
ManagedHandle handle;
|
||||
|
||||
public void FromManaged(T[]? managed)
|
||||
{
|
||||
if (managed == null)
|
||||
return;
|
||||
managedArray = managed;
|
||||
unmanagedArray = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
|
||||
handle = ManagedHandle.Alloc(unmanagedArray);
|
||||
}
|
||||
|
||||
public ReadOnlySpan<T> GetManagedValuesSource() => managedArray;
|
||||
|
||||
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
|
||||
{
|
||||
if (unmanagedArray == null)
|
||||
return Span<TUnmanagedElement>.Empty;
|
||||
return unmanagedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)ManagedHandle.ToIntPtr(handle);
|
||||
|
||||
public void FromUnmanaged(TUnmanagedElement* unmanaged)
|
||||
{
|
||||
ManagedArray arr = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
if (managedArray == null || managedArray.Length != arr.Length)
|
||||
managedArray = new T[arr.Length];
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
|
||||
{
|
||||
if (unmanagedArray == null)
|
||||
return ReadOnlySpan<TUnmanagedElement>.Empty;
|
||||
return unmanagedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public Span<T> GetManagedValuesDestination(int numElements) => managedArray;
|
||||
|
||||
public T[] ToManaged() => managedArray;
|
||||
|
||||
public void Free()
|
||||
{
|
||||
unmanagedArray.FreePooled();
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
|
||||
{
|
||||
if (managed is null)
|
||||
{
|
||||
numElements = 0;
|
||||
return null;
|
||||
}
|
||||
numElements = managed.Length;
|
||||
ManagedArray managedArray = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
|
||||
IntPtr handle = ManagedHandle.ToIntPtr(managedArray);
|
||||
return (TUnmanagedElement*)handle;
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[]? managed) => managed;
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return Span<TUnmanagedElement>.Empty;
|
||||
ManagedArray unmanagedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
return unmanagedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements];
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[]? managed) => managed;
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return ReadOnlySpan<TUnmanagedElement>.Empty;
|
||||
ManagedArray array = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
return array.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public static void Free(TUnmanagedElement* unmanaged)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return;
|
||||
ManagedHandle handle = ManagedHandle.FromIntPtr(new IntPtr(unmanaged));
|
||||
Unsafe.As<ManagedArray>(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))]
|
||||
public 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)
|
||||
{
|
||||
return managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
|
||||
public static IntPtr ConvertToUnmanaged(string managed) => ManagedString.ToNative(managed);
|
||||
public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
|
||||
|
||||
public static string ToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
|
||||
public static IntPtr ToNative(string managed) => ManagedString.ToNative(managed);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
1076
Source/Engine/Engine/NativeInterop.Unmanaged.cs
Normal file
1076
Source/Engine/Engine/NativeInterop.Unmanaged.cs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1451,7 +1451,7 @@ namespace Flax.Build.Bindings
|
||||
else if (type == "bool")
|
||||
type = "byte";
|
||||
else if (type == "object")
|
||||
type = "VariantNative";
|
||||
type = "NativeVariant";
|
||||
else if (internalType)
|
||||
{
|
||||
internalTypeMarshaler = type + "Marshaller";
|
||||
@@ -1468,8 +1468,8 @@ namespace Flax.Build.Bindings
|
||||
if (fieldInfo.NoArray && fieldInfo.Type.IsArray)
|
||||
continue;
|
||||
|
||||
if (type == "VariantNative")
|
||||
continue; // FIXME
|
||||
if (type == "NativeVariant")
|
||||
continue; // TODO: FIXME
|
||||
|
||||
if (useSeparator)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user