From 43c4d45080fe4d49d93eaab0081f4c372e87955b Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Mon, 5 Jan 2026 15:01:51 +0200 Subject: [PATCH] prog --- .../Engine/NativeInterop.Marshallers.cs | 1 + .../Engine/Engine/NativeInterop.Unmanaged.cs | 5 +- Source/Engine/Engine/NativeInterop.cs | 265 +++++++++++++++--- 3 files changed, 226 insertions(+), 45 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 18f448233..e95cdbe05 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -40,6 +40,7 @@ namespace FlaxEngine.Interop object managed = ManagedHandle.FromIntPtr(unmanaged).Target; if (managed is ManagedArray managedArray) { + throw new Exception("not supported"); var managedArrayHandle = ManagedHandle.Alloc(managedArray, GCHandleType.Normal); managed = NativeInterop.MarshalToManaged((IntPtr)managedArrayHandle, managedArray.ArrayType); managedArrayHandle.Free(); diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 629b3e4c1..99538a44c 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -807,8 +807,11 @@ namespace FlaxEngine.Interop { // The internal exception thrown in MethodInfo.Invoke is caught here Exception realException = exception; - if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker") + if (exception.InnerException != null && + (exception.TargetSite.ReflectedType.Name == "MethodInvoker" || exception.TargetSite.ReflectedType.Name == "MethodBaseInvoker")) + { realException = exception.InnerException; + } if (exceptionPtr != IntPtr.Zero) Unsafe.Write(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak)); diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 76159ebd8..6c2de55ba 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -21,6 +21,7 @@ using System.Threading; using System.Buffers; using System.Runtime.InteropServices.Marshalling; using FlaxEngine.Utilities; +using System.Diagnostics; namespace FlaxEngine.Interop { @@ -412,7 +413,86 @@ namespace FlaxEngine.Interop internal static ConcurrentDictionary toNativeMarshallers = new ConcurrentDictionary(1, 3); internal static ConcurrentDictionary toNativeFieldMarshallers = new ConcurrentDictionary(1, 3); - internal static ConcurrentDictionary)> _marshallers = new(1, 3); + + + + + + + + + internal static ConcurrentDictionary, Func)> _marshallers = new(1, 3); + + internal static class NewMarshalHelperValueType where TSource : struct + { + internal static object NativeToManaged9(object src) + { + return NewMarshalHelper.NativeToManaged9(ref Unsafe.Unbox(src)); + } + } + + internal static class NewMarshalHelperReferenceType where TSource : class + { + internal static object NativeToManaged9(object src) + { + TSource tsrc = Unsafe.As(src); + return NewMarshalHelper.NativeToManaged9(ref tsrc); + } + } + + internal static class NewMarshalHelper + { + internal static Func _nativeToManagedFunc; + internal static Type _pointerType; + + internal static void Init(MethodInfo nativeToManagedMethod) + { + //Assert.IsNull(_nativeToManagedFunc); + + //var internalType = nativeToManagedMethod.GetParameters()[0].ParameterType; + //var types = new Type[] { marshalType, internalType }; + //var convertDelegate = method.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(types)); + + if (_nativeToManagedFunc == null && nativeToManagedMethod != null) + _nativeToManagedFunc = nativeToManagedMethod.CreateDelegate>(); + + _pointerType = typeof(TDest).MakePointerType(); + } + + internal static TDest NativeToManaged9(ref TSource src) + { + return _nativeToManagedFunc(src); + } + + internal static object NativeToManagedIntPtr(TSource src) + { + // typeof(TSource) == typeof(IntPtr) + return _nativeToManagedFunc(src); + } + + internal static object NativeToManagedPointer(IntPtr src) + { + //byte* asd = null; + //return asd; + return Pointer.Box(src.ToPointer(), _pointerType); + } + + internal static object NativeToManagedByPass(TSource src) => src; + + internal static object NativeToManaged(IntPtr src) + { + // typeof(TSource) != typeof(IntPtr) + TSource native = Marshal.PtrToStructure(src); + return _nativeToManagedFunc(native); + } + + internal static object NativeToManagedDirect(IntPtr src) + { + // typeof(TSource) != typeof(IntPtr) + TSource native = Unsafe.Read(src.ToPointer()); + return native; + } + } internal static object MarshalToManaged2(IntPtr nativePtr, Type type) { @@ -432,6 +512,10 @@ namespace FlaxEngine.Interop { if (type == typeof(bool)) return typeof(BooleanMarshaller); + else if (type == typeof(string)) + return typeof(StringMarshaller); // UTF-16 strings via MMethod::Invoke + else if (type == typeof(object)) + return typeof(AsManagedHandleMarshaller); else if (type.IsArray) return null; @@ -441,12 +525,13 @@ namespace FlaxEngine.Interop return marshallerType; } - static (Type, Func) Factory2(Type type) + static (Type, Func, Func) Factory2(Type type) { Type marshalType = type; if (marshalType.IsByRef) marshalType = marshalType.GetElementType(); - else if (marshalType == typeof(byte*) || marshalType == typeof(char*)) + + if (marshalType == typeof(byte*) || marshalType == typeof(char*)) { } else if (marshalType.IsPointer) @@ -473,17 +558,63 @@ namespace FlaxEngine.Interop { if (marshalType == typeof(IntPtr)) { + //var setup = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(IntPtr), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + //setup.Invoke(null, [method]); + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(IntPtr), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedByPass), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + Func func = (obj) => obj; - return (typeof(IntPtr), func); + return (typeof(IntPtr), func, convdirectdel); } else if (marshalType == typeof(ManagedHandle)) { + var methody = typeof(ManagedHandle).GetMethod(nameof(ManagedHandle.FromIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var setup = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(ManagedHandle), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + setup.Invoke(null, [methody]); + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(ManagedHandle), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + Func func = (obj) => ManagedHandle.FromIntPtr((IntPtr)obj); - return (typeof(IntPtr), func); + return (typeof(IntPtr), func, convdirectdel); } + else if (marshalType.IsPointer) + { + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(IntPtr), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedDirect), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + + Func func = (obj) => obj; + return (typeof(IntPtr), func, convdirectdel); + //return (null, null, null); + /*var setup = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType.GetElementType(), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + setup.Invoke(null, [null]); + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType.GetElementType(), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedPointer), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + return (marshalType, null, convdirectdel);*/ + } + else if (marshalType.IsPrimitive || marshalType.IsEnum) + { + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType, marshalType]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedDirect), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + return (marshalType, null, convdirectdel); + } + else if (!marshalType.IsArray && IsBlittable(marshalType)) + { + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType, marshalType]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedDirect), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + return (marshalType, null, convdirectdel); + } + + /*else if (marshalType == typeof(object)) + { + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(ManagedHandle), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + + Func func = (obj) => (IntPtr)obj != IntPtr.Zero ? ManagedHandle.FromIntPtr((IntPtr)obj).Target : null; + return (typeof(IntPtr), func, null); + }*/ } if (marshallerType == null) - return (null, null); + return (null, null, null); MethodInfo method = marshallerType.GetMethod("ConvertToManaged", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); if (method == null) @@ -502,71 +633,116 @@ namespace FlaxEngine.Interop } } - return (null, null); + return (null, null, null); } var internalType = method.GetParameters()[0].ParameterType; var types = new Type[] { marshalType, internalType }; var convertDelegate = method.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(types)); - if (internalType.IsStructure()) + + var minit = typeof(NewMarshalHelper<,>).MakeGenericType(types).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + minit.Invoke(null, [method]); + var conv = typeof(NewMarshalHelper<,>).MakeGenericType(types).GetMethod(nameof(NewMarshalHelper<,>.NativeToManaged), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdel = conv.CreateDelegate>(); + + + if (internalType == typeof(IntPtr)) + { + var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType(types).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + var convdirectdel = convdirect.CreateDelegate>(); + + Func func = + (obj) => convertDelegate.DynamicInvoke(obj); + + return (internalType, func, convdirectdel); + } + else if (internalType.IsStructure()) { Func func = (obj) => convertDelegate.DynamicInvoke(obj); - return (internalType, func); + + return (internalType, func, convdel); } else { Func func = (obj) => convertDelegate.DynamicInvoke(obj); - return (internalType, func); + return (internalType, func, convdel); } } var type2 = type.IsByRef ? type.GetElementType() : type; + /*if (type2.IsPrimitive) + { + if (type.IsByRef && type2 == typeof(IntPtr)) + nativePtr = Unsafe.Read(nativePtr.ToPointer()); + + //ref byte src = ref Unsafe.AsRef(nativePtr.ToPointer()); + //var ret = RuntimeHelpers.Box(ref src, type.TypeHandle); + var ret = Marshal.PtrToStructure(nativePtr, type2); + return ret; + } + else if (type2.IsEnum) + { + if (type.IsByRef) + type2 = type2; + ref byte src = ref Unsafe.AsRef(nativePtr.ToPointer()); + var ret = RuntimeHelpers.Box(ref src, type2.TypeHandle); + return ret; + }*/ if (!_marshallers.TryGetValue(type, out var marsh)) marsh = _marshallers.GetOrAdd(type, Factory2); - if (!toManagedMarshallers.TryGetValue(type, out var deleg)) - deleg = toManagedMarshallers.GetOrAdd(type, Factory); - - if (marsh.Item2 != null) - { - object conv1 = deleg(nativePtr, type.IsByRef && false); - if (type.IsByRef && marsh.Item1 == typeof(IntPtr)) - nativePtr = Unsafe.Read(nativePtr.ToPointer()); - object value = marsh.Item1 == typeof(IntPtr) ? nativePtr : Marshal.PtrToStructure(nativePtr, marsh.Item1);//Unsafe.Read(nativePtr.ToPointer()); - object conv2 = marsh.Item2(value); - if (conv1 is null && conv2 is null) - { } - else if (!conv1.Equals(conv2)) - Assert.IsTrue(conv1.Equals(conv2)); - return conv2; - } - else if (type2 == typeof(bool)) + if (marsh.Item3 != null) { //object conv1 = deleg(nativePtr, type.IsByRef && false); - byte value = Unsafe.Read(nativePtr.ToPointer()); - object conv2 = BooleanMarshaller.ConvertToManaged(value); - //Assert.IsTrue(conv1.Equals(conv2)); - return conv2; - } - else if (type2 == typeof(ManagedHandle)) - { - //ManagedHandle conv1 = (ManagedHandle)deleg(nativePtr, type.IsByRef && false); - ManagedHandle conv2 = ManagedHandle.FromIntPtr(nativePtr); - //Assert.IsTrue(conv1.Equals(conv2)); - return conv2; - } - else if (type2 == typeof(int) || type2.IsEnum || - type2 == typeof(IntPtr) || type2 == typeof(Float2) || type2 == typeof(Float3) || type2 == typeof(Guid)) - { + if (type.IsByRef && marsh.Item1 == typeof(IntPtr)) + nativePtr = Unsafe.Read(nativePtr.ToPointer()); + if (true && marsh.Item3 != null) + { + // TODO: CustomMarshaller.Free() + return marsh.Item3(nativePtr); + } + else + { + object value = marsh.Item1 == typeof(IntPtr) ? nativePtr : Marshal.PtrToStructure(nativePtr, marsh.Item1); + object conv2 = marsh.Item2(value); + // TODO: CustomMarshaller.Free() + return conv2; + } + /*if (conv1 is null && conv2 is null) + { } + else if (!conv1.Equals(conv2)) + Assert.IsTrue(conv1.Equals(conv2));*/ + + + } + if (type2.IsStructure()) + { + var ret = Marshal.PtrToStructure(nativePtr, type2); + return ret; + } + + + if (type2 == typeof(int) || type2.IsEnum + || type2 == typeof(IntPtr) || type2 == typeof(Float2) || type2 == typeof(Float3) + || type2 == typeof(long) || type2 == typeof(sbyte) + || type2 == typeof(uint) || type2 == typeof(ulong) || type2 == typeof(ushort) || type2 == typeof(byte) + || type2 == typeof(float) || type2 == typeof(double)) + { + // TODO + } + else if (type2 == typeof(byte*) || type2 == typeof(Guid) || type2.IsArray) + { + // TODO } else { } - + if (!toManagedMarshallers.TryGetValue(type, out var deleg)) + deleg = toManagedMarshallers.GetOrAdd(type, Factory); return deleg(nativePtr, type.IsByRef && false); } @@ -1640,7 +1816,8 @@ namespace FlaxEngine.Interop internal static void ToNativeString(ref string managedValue, IntPtr nativePtr) { - Unsafe.Write(nativePtr.ToPointer(), ManagedString.ToNative/*Weak*/(managedValue)); + //Unsafe.Write(nativePtr.ToPointer(), ManagedString.ToNative/*Weak*/(managedValue)); + Unsafe.Write(nativePtr.ToPointer(), new NativeString(managedValue)); } internal static void ToNativeType(ref Type managedValue, IntPtr nativePtr)