diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index ff0997eaa..22ec90f98 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -18,7 +18,7 @@ using System.Collections; using System.Buffers; using System.Collections.Concurrent; -[assembly: DisableRuntimeMarshalling] +#pragma warning disable 1591 namespace FlaxEngine { @@ -361,7 +361,7 @@ namespace FlaxEngine [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 GCHandleMarshaller { public static class NativeToManaged { @@ -398,11 +398,11 @@ namespace FlaxEngine 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) + 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 ? GCHandle.FromIntPtr(managed).Target : null; + public static IntPtr ToNative(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero; + public static void Free(IntPtr unmanaged) { if (unmanaged == IntPtr.Zero) return; @@ -411,7 +411,7 @@ namespace FlaxEngine } [CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))] - internal static class SystemTypeMarshaller + public static class SystemTypeMarshaller { internal static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged)); @@ -420,7 +420,7 @@ namespace FlaxEngine if (managed == null) return IntPtr.Zero; - GCHandle handle = NativeInterop.GetOrAddTypeGCHandle(managed); + GCHandle handle = NativeInterop.GetTypeGCHandle(managed); return GCHandle.ToIntPtr(handle); } @@ -431,7 +431,7 @@ namespace FlaxEngine } [CustomMarshaller(typeof(Exception), MarshalMode.Default, typeof(ExceptionMarshaller))] - internal static class ExceptionMarshaller + public static class ExceptionMarshaller { internal static Exception ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged)); internal static IntPtr ConvertToUnmanaged(Exception managed) => GCHandleMarshaller.ConvertToUnmanaged(managed); @@ -444,7 +444,7 @@ namespace FlaxEngine [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 ObjectMarshaller { public static class NativeToManaged { @@ -457,7 +457,7 @@ namespace FlaxEngine } [CustomMarshaller(typeof(CultureInfo), MarshalMode.Default, typeof(CultureInfoMarshaller))] - internal static class CultureInfoMarshaller + public static class CultureInfoMarshaller { internal static CultureInfo ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged)); internal static IntPtr ConvertToUnmanaged(CultureInfo managed) => GCHandleMarshaller.ConvertToUnmanaged(managed); @@ -466,7 +466,7 @@ namespace FlaxEngine [CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedIn, typeof(SystemArrayMarshaller.ManagedToNative))] [CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedOut, typeof(SystemArrayMarshaller.ManagedToNative))] - internal static class SystemArrayMarshaller + public static class SystemArrayMarshaller { public struct ManagedToNative { @@ -508,7 +508,7 @@ namespace FlaxEngine [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 unsafe class DictionaryMarshaller { public static class NativeToManaged { @@ -568,7 +568,7 @@ namespace FlaxEngine [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 unsafe class ArrayMarshaller where TUnmanagedElement : unmanaged { public static class NativeToManaged { @@ -706,7 +706,7 @@ namespace FlaxEngine } } - internal static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { if (managed is null) { @@ -722,9 +722,9 @@ namespace FlaxEngine return (TUnmanagedElement*)handle; } - internal static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; + public static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; - internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { if (unmanaged == null) return Span.Empty; @@ -733,11 +733,11 @@ namespace FlaxEngine return unmanagedArray.GetSpan(); } - internal static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements]; + public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements]; - internal static Span GetManagedValuesDestination(T[]? managed) => managed; + public static Span GetManagedValuesDestination(T[]? managed) => managed; - internal static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) + public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) { if (unmanaged == null) return ReadOnlySpan.Empty; @@ -746,7 +746,7 @@ namespace FlaxEngine return array.GetSpan(); } - internal static void Free(TUnmanagedElement* unmanaged) + public static void Free(TUnmanagedElement* unmanaged) { if (unmanaged == null) return; @@ -766,7 +766,7 @@ namespace FlaxEngine [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 StringMarshaller { public static class NativeToManaged { @@ -812,12 +812,12 @@ namespace FlaxEngine 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); + 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); - internal static string ToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged); - internal static IntPtr ToNative(string managed) => ManagedString.ToNative(managed); + public static string ToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged); + public static IntPtr ToNative(string managed) => ManagedString.ToNative(managed); } #endregion @@ -1468,12 +1468,12 @@ namespace FlaxEngine if (Pointer.Unbox(managedValue) == null) managedPtr = IntPtr.Zero; else if (managedValue is FlaxEngine.Object flaxObj) - managedPtr = flaxObj.__unmanagedPtr; + managedPtr = FlaxEngine.Object.GetUnmanagedPtr(flaxObj); else managedPtr = GCHandle.ToIntPtr(GCHandle.Alloc(managedValue, GCHandleType.Weak)); } else if (type == typeof(Type)) - managedPtr = managedValue != null ? GCHandle.ToIntPtr(GetOrAddTypeGCHandle((Type)(object)managedValue)) : IntPtr.Zero; + managedPtr = managedValue != null ? GCHandle.ToIntPtr(GetTypeGCHandle((Type)(object)managedValue)) : IntPtr.Zero; else managedPtr = managedValue != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managedValue, GCHandleType.Weak)) : IntPtr.Zero; @@ -1567,7 +1567,7 @@ namespace FlaxEngine bool isInterface = type.IsInterface; bool isAbstract = type.IsAbstract; - GCHandle typeHandle = GetOrAddTypeGCHandle(type); + GCHandle typeHandle = GetTypeGCHandle(type); NativeClassDefinitions managedClass = new NativeClassDefinitions() { @@ -1588,7 +1588,7 @@ namespace FlaxEngine internal static unsafe void GetManagedClassFromType(IntPtr typeHandle, NativeClassDefinitions* managedClass, IntPtr* assemblyHandle) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); - GCHandle classTypeHandle = GetOrAddTypeGCHandle(type); + GCHandle classTypeHandle = GetTypeGCHandle(type); *managedClass = new NativeClassDefinitions() { @@ -1666,7 +1666,7 @@ namespace FlaxEngine { name = Marshal.StringToCoTaskMemAnsi(fieldHolder.field.Name), fieldHandle = GCHandle.ToIntPtr(fieldHandle), - fieldTypeHandle = GCHandle.ToIntPtr(GetOrAddTypeGCHandle(fieldHolder.field.FieldType)), + fieldTypeHandle = GCHandle.ToIntPtr(GetTypeGCHandle(fieldHolder.field.FieldType)), fieldAttributes = (uint)fieldHolder.field.Attributes, }; Unsafe.Write(ptr.ToPointer(), classField); @@ -1726,7 +1726,7 @@ namespace FlaxEngine attributeHandle = GCHandle.Alloc(attributeValues[i]); classAttributesCacheCollectible.Add(attributeValues[i], attributeHandle); } - GCHandle attributeTypeHandle = GetOrAddTypeGCHandle(attributeTypes[i]); + GCHandle attributeTypeHandle = GetTypeGCHandle(attributeTypes[i]); NativeAttributeDefinitions classAttribute = new NativeAttributeDefinitions() { @@ -1792,7 +1792,7 @@ namespace FlaxEngine IntPtr arr = Marshal.AllocCoTaskMem(IntPtr.Size * methodHolder.parameterTypes.Length); for (int i = 0; i < methodHolder.parameterTypes.Length; i++) { - GCHandle typeHandle = GetOrAddTypeGCHandle(methodHolder.parameterTypes[i]); + GCHandle typeHandle = GetTypeGCHandle(methodHolder.parameterTypes[i]); Marshal.WriteIntPtr(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i), GCHandle.ToIntPtr(typeHandle)); } *typeHandles = arr; @@ -1948,7 +1948,7 @@ namespace FlaxEngine { var obj = GCHandle.FromIntPtr(handle).Target; Type classType = obj.GetType(); - return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(classType)); + return GCHandle.ToIntPtr(GetTypeGCHandle(classType)); } internal static class ValueTypeUnboxer @@ -2014,8 +2014,6 @@ namespace FlaxEngine internal static IntPtr InvokeMethod(IntPtr instancePtr, IntPtr methodHandle, IntPtr paramPtr, IntPtr exceptionPtr) { MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); - - if (methodHolder.TryGetDelegate(out var methodDelegate, out var methodDelegateContext)) { // Fast path, invoke the method with minimal allocations @@ -2086,7 +2084,7 @@ namespace FlaxEngine else if (methodHolder.method.ReturnType == typeof(bool)) return (bool)returnObject ? boolTruePtr : boolFalsePtr; else if (methodHolder.method.ReturnType == typeof(Type)) - return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnObject))); + return GCHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))); else if (methodHolder.method.ReturnType == typeof(object[])) return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); else @@ -2539,7 +2537,7 @@ namespace FlaxEngine /// /// Returns a static GCHandle for given Type, and caches it if needed. /// - internal static GCHandle GetOrAddTypeGCHandle(Type type) + internal static GCHandle GetTypeGCHandle(Type type) { if (typeHandleCache.TryGetValue(type, out GCHandle handle)) return handle; @@ -2556,20 +2554,6 @@ namespace FlaxEngine return handle; } - /// - /// Returns a static GCHandle for given Type. - /// - internal static GCHandle GetTypeGCHandle(Type type) - { - if (typeHandleCache.TryGetValue(type, out GCHandle handle)) - return handle; - - if (typeHandleCacheCollectible.TryGetValue(type, out handle)) - return handle; - - throw new Exception($"GCHandle not found for type '{type.FullName}'"); - } - private static class DelegateHelpers { private static readonly Func MakeNewCustomDelegateFunc = @@ -2696,7 +2680,7 @@ namespace FlaxEngine else if (method.ReturnType == typeof(bool)) return (bool)returnObject ? boolTruePtr : boolFalsePtr; else if (method.ReturnType == typeof(Type)) - return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnObject))); + return GCHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))); else if (method.ReturnType == typeof(object[])) return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); else diff --git a/Source/Engine/Engine/NativeInterop_Invoker.cs b/Source/Engine/Engine/NativeInterop_Invoker.cs index 1426565ef..ccbe468d9 100644 --- a/Source/Engine/Engine/NativeInterop_Invoker.cs +++ b/Source/Engine/Engine/NativeInterop_Invoker.cs @@ -58,7 +58,7 @@ namespace FlaxEngine else if (typeof(TRet) == typeof(bool)) return (bool)(object)returnValue ? boolTruePtr : boolFalsePtr; else if (typeof(TRet) == typeof(Type)) - return returnValue != null ? GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnValue))) : IntPtr.Zero; + return returnValue != null ? GCHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnValue))) : IntPtr.Zero; else if (typeof(TRet) == typeof(object[])) return returnValue != null ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnValue))), GCHandleType.Weak)) : IntPtr.Zero; else diff --git a/Source/Engine/Scripting/Object.cs b/Source/Engine/Scripting/Object.cs index 5847bb78c..671e54352 100644 --- a/Source/Engine/Scripting/Object.cs +++ b/Source/Engine/Scripting/Object.cs @@ -22,7 +22,7 @@ namespace FlaxEngine /// The pointer to the unmanaged object (native C++ instance). /// [NonSerialized] - internal readonly IntPtr __unmanagedPtr; + protected readonly IntPtr __unmanagedPtr; /// /// The object unique identifier. @@ -240,8 +240,8 @@ namespace FlaxEngine /// /// The pointer to the unmanaged (native) object. /// The object. - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern Object FromUnmanagedPtr(IntPtr ptr); + [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::FromUnmanagedPtr", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] + public static partial Object FromUnmanagedPtr(IntPtr ptr); /// public override int GetHashCode() diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 0400b5b2e..d4323712b 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -762,6 +762,7 @@ public: static MonoObject* FromUnmanagedPtr(ScriptingObject* obj) { + SCRIPTING_EXPORT("FlaxEngine.Object::FromUnmanagedPtr") MonoObject* result = nullptr; if (obj) result = obj->GetOrCreateManagedInstance(); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 890f0524b..584176f51 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -17,6 +17,7 @@ namespace Flax.Build.Bindings private static readonly List CSharpUsedNamespacesSorted = new List(); private static readonly List CSharpAdditionalCode = new List(); private static readonly Dictionary CSharpAdditionalCodeCache = new Dictionary(); + private static string CSharpLastAssembly; public static event Action GenerateCSharpTypeInternals; @@ -1986,10 +1987,16 @@ namespace Flax.Build.Bindings CSharpUsedNamespaces.Add("System.Globalization"); CSharpUsedNamespaces.Add("System.Runtime.CompilerServices"); CSharpUsedNamespaces.Add("System.Runtime.InteropServices"); + CSharpUsedNamespaces.Add("FlaxEngine"); #if USE_NETCORE CSharpUsedNamespaces.Add("System.Runtime.InteropServices.Marshalling"); + if (CSharpLastAssembly != moduleInfo.Name) + { + // Add custom assembly attributes here, once per assembly + contents.AppendLine("[assembly: DisableRuntimeMarshalling]"); + CSharpLastAssembly = moduleInfo.Name; + } #endif - CSharpUsedNamespaces.Add("FlaxEngine"); // Process all API types from the file var useBindings = false;