diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 6e7fbb3e8..82359e1b4 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -15,8 +15,8 @@ namespace FlaxEngine.Interop #if FLAX_EDITOR [HideInEditor] #endif - [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedHandleMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(ManagedHandleMarshaller.ManagedToNative))] + [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedHandleMarshaller.ManagedToNativeState))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(ManagedHandleMarshaller.ManagedToNativeState))] [CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(ManagedHandleMarshaller.ManagedToNative))] [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(ManagedHandleMarshaller.NativeToManaged))] [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(ManagedHandleMarshaller.NativeToManaged))] @@ -31,7 +31,20 @@ namespace FlaxEngine.Interop #endif public static class NativeToManaged { - public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target; + public static object ConvertToManaged(IntPtr unmanaged) + { + if (unmanaged == IntPtr.Zero) + return null; + object managed = ManagedHandle.FromIntPtr(unmanaged).Target; + if (managed is ManagedArray managedArray) + { + var managedArrayHandle = ManagedHandle.Alloc(managedArray, GCHandleType.Normal); + managed = NativeInterop.MarshalToManaged((IntPtr)managedArrayHandle, managedArray.ArrayType); + managedArrayHandle.Free(); + } + return managed; + } + public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero; public static void Free(IntPtr unmanaged) @@ -40,6 +53,52 @@ namespace FlaxEngine.Interop } } + +#if FLAX_EDITOR + [HideInEditor] +#endif + public struct ManagedToNativeState + { + ManagedArray managedArray; + IntPtr handle; + + public void FromManaged(object managed) + { + if (managed == null) + return; + if (managed is Array arr) + { + var type = managed.GetType(); + var elementType = type.GetElementType(); + if (NativeInterop.ArrayFactory.GetMarshalledType(elementType) == elementType) + { + // Use pooled managed array wrapper to be passed around as handle to it + (ManagedHandle tmp, managedArray) = ManagedArray.WrapPooledArray(arr); + handle = ManagedHandle.ToIntPtr(tmp); + } + else + { + // Convert array contents to be properly accessed by the native code (as GCHandles array) + managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(arr); + handle = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray)); + managedArray = null; // It's not pooled + } + } + else + handle = ManagedHandle.ToIntPtr(managed, GCHandleType.Weak); + } + + public IntPtr ToUnmanaged() + { + return handle; + } + + public void Free() + { + managedArray?.FreePooled(); + } + } + #if FLAX_EDITOR [HideInEditor] #endif @@ -50,12 +109,6 @@ namespace FlaxEngine.Interop public static void Free(IntPtr unmanaged) { - // This is a weak handle, no need to free it - /* - if (unmanaged == IntPtr.Zero) - return; - ManagedHandle.FromIntPtr(unmanaged).Free(); - */ } } @@ -342,6 +395,7 @@ namespace FlaxEngine.Interop { public static Dictionary ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller.ToManaged(unmanaged); public static IntPtr ConvertToUnmanaged(Dictionary managed) => DictionaryMarshaller.ToNative(managed, GCHandleType.Weak); + public static void Free(IntPtr unmanaged) { //DictionaryMarshaller.Free(unmanaged); // No need to free weak handles @@ -614,6 +668,7 @@ namespace FlaxEngine.Interop { public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged); public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak); + public static void Free(IntPtr unmanaged) { //ManagedString.Free(unmanaged); // No need to free weak handles diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index db7bac446..eadd45fbc 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -1459,8 +1459,8 @@ namespace Flax.Build.Bindings public static class NativeToManaged { public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged)); - public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed); - public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.NativeToManaged.Free(unmanaged); + public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero; + public static void Free(IntPtr unmanaged) {} } #if FLAX_EDITOR [HideInEditor] @@ -1468,8 +1468,8 @@ namespace Flax.Build.Bindings public static class ManagedToNative { public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged)); - public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed); - public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.ManagedToNative.Free(unmanaged); + public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero; + public static void Free(IntPtr unmanaged) {} } #if FLAX_EDITOR [HideInEditor]