diff --git a/Source/Engine/Engine/NativeInterop.Invoker.cs b/Source/Engine/Engine/NativeInterop.Invoker.cs index 1c5b3e453..2fc54597c 100644 --- a/Source/Engine/Engine/NativeInterop.Invoker.cs +++ b/Source/Engine/Engine/NativeInterop.Invoker.cs @@ -18,6 +18,8 @@ namespace FlaxEngine.Interop /// internal static class Invoker { + // TODO: Use .NET8 Unsafe.BitCast(returnValue) for more efficient casting of value types over boxing cast + internal static IntPtr MarshalReturnValue(ref TRet returnValue) { if (returnValue == null) diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 2eb467c10..148f02539 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -141,7 +141,7 @@ namespace FlaxEngine.Interop public static class ManagedToNative { - public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => (object)managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero; + public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero; } } diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index ca94bed04..86ec03a65 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -770,12 +770,20 @@ namespace FlaxEngine.Interop } [UnmanagedCallersOnly] - internal static void SetArrayValueReference(ManagedHandle arrayHandle, IntPtr valueHandle, int index) + internal static void WriteArrayReference(ManagedHandle arrayHandle, IntPtr valueHandle, int index) { ManagedArray managedArray = Unsafe.As(arrayHandle.Target); managedArray.ToSpan()[index] = valueHandle; } + [UnmanagedCallersOnly] + internal static void WriteArrayReferences(ManagedHandle arrayHandle, IntPtr spanPtr, int spanLength) + { + ManagedArray managedArray = Unsafe.As(arrayHandle.Target); + var unmanagedSpan = new Span(spanPtr.ToPointer(), spanLength); + unmanagedSpan.CopyTo(managedArray.ToSpan()); + } + [UnmanagedCallersOnly] internal static ManagedHandle LoadAssemblyImage(IntPtr assemblyPathPtr, IntPtr* assemblyName, IntPtr* assemblyFullName) { diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.h b/Source/Engine/Scripting/ManagedCLR/MCore.h index 6bc430f0e..88124a223 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.h +++ b/Source/Engine/Scripting/ManagedCLR/MCore.h @@ -112,6 +112,7 @@ public: static void WriteRef(void* ptr, MObject* ref); static void WriteValue(void* dst, void* src, int32 count, const MClass* klass); static void WriteArrayRef(MArray* dst, MObject* ref, int32 index); + static void WriteArrayRef(MArray* dst, Span span); #if USE_NETCORE static void* AllocateMemory(int32 size, bool coTaskMem = false); static void FreeMemory(void* ptr, bool coTaskMem = false); diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.h b/Source/Engine/Scripting/ManagedCLR/MUtils.h index 8e7b65a60..90bfa5327 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.h +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.h @@ -104,8 +104,14 @@ struct MConverter void ToManagedArray(MArray* result, const Span& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, (MObject*)MUtils::ToString(data[i]), i); + objects[i] = (MObject*)MUtils::ToString(data[i]); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } void ToNativeArray(Span& result, const MArray* data) @@ -132,8 +138,14 @@ struct MConverter void ToManagedArray(MArray* result, const Span& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, (MObject*)MUtils::ToString(data[i]), i); + objects[i] = (MObject*)MUtils::ToString(data[i]); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } void ToNativeArray(Span& result, const MArray* data) @@ -160,8 +172,14 @@ struct MConverter void ToManagedArray(MArray* result, const Span& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, (MObject*)MUtils::ToString(data[i]), i); + objects[i] = (MObject*)MUtils::ToString(data[i]); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } void ToNativeArray(Span& result, const MArray* data) @@ -188,8 +206,14 @@ struct MConverter void ToManagedArray(MArray* result, const Span& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, MUtils::BoxVariant(data[i]), i); + objects[i] = MUtils::BoxVariant(data[i]); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } void ToNativeArray(Span& result, const MArray* data) @@ -216,8 +240,14 @@ struct MConverter::Va void ToManagedArray(MArray* result, const Span& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, data[i] ? data[i]->GetOrCreateManagedInstance() : nullptr, i); + objects[i] = data[i] ? data[i]->GetOrCreateManagedInstance() : nullptr; + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } void ToNativeArray(Span& result, const MArray* data) @@ -239,8 +269,14 @@ struct MConverter::Val void ToManagedArray(MArray* result, const Span& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, data[i].GetOrCreateManagedInstance(), i); + objects[i] = data[i].GetOrCreateManagedInstance(); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } }; @@ -263,8 +299,16 @@ struct MConverter> void ToManagedArray(MArray* result, const Span>& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, data[i].GetManagedInstance(), i); + objects[i] = data[i].GetManagedInstance(); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); + //for (int32 i = 0; i < data.Length(); i++) + // MCore::GC::WriteArrayRef(result, data[i].GetManagedInstance(), i); } void ToNativeArray(Span>& result, const MArray* data) @@ -294,8 +338,14 @@ struct MConverter> void ToManagedArray(MArray* result, const Span>& data) { + if (data.Length() == 0) + return; + + Array objects; + objects.Resize(data.Length(), false); for (int32 i = 0; i < data.Length(); i++) - MCore::GC::WriteArrayRef(result, data[i].GetManagedInstance(), i); + objects[i] = data[i].GetManagedInstance(); + MCore::GC::WriteArrayRef(result, Span(objects.Get(), objects.Count())); } void ToNativeArray(Span>& result, const MArray* data) diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index d65af6ed6..3ae1e02d5 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -466,8 +466,14 @@ void MCore::GC::WriteValue(void* dst, void* src, int32 count, const MClass* klas void MCore::GC::WriteArrayRef(MArray* dst, MObject* ref, int32 index) { - static void* SetArrayValueReferencePtr = GetStaticMethodPointer(TEXT("SetArrayValueReference")); - CallStaticMethod(SetArrayValueReferencePtr, dst, ref, index); + static void* WriteArrayReferencePtr = GetStaticMethodPointer(TEXT("WriteArrayReference")); + CallStaticMethod(WriteArrayReferencePtr, dst, ref, index); +} + +void MCore::GC::WriteArrayRef(MArray* dst, Span refs) +{ + static void* WriteArrayReferencesPtr = GetStaticMethodPointer(TEXT("WriteArrayReferences")); + CallStaticMethod(WriteArrayReferencesPtr, dst, refs.Get(), refs.Length()); } void* MCore::GC::AllocateMemory(int32 size, bool coTaskMem) diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp index 05c01fd8a..54892b11b 100644 --- a/Source/Engine/Scripting/Runtime/Mono.cpp +++ b/Source/Engine/Scripting/Runtime/Mono.cpp @@ -869,6 +869,13 @@ void MCore::GC::WriteArrayRef(MArray* dst, MObject* ref, int32 index) mono_gc_wbarrier_set_arrayref(dst, (byte*)ptr + index * sizeof(void*), ref); } +void MCore::GC::WriteArrayRef(MArray* dst, Span refs) +{ + void* ptr = mono_array_addr_with_size(dst, 0, 0); + for (int32 index = 0; index < refs.Length(); index++) + mono_gc_wbarrier_set_arrayref(dst, (byte*)ptr + index * sizeof(void*), refs[index]); +} + void MCore::Thread::Attach() { if (!IsInMainThread() && !mono_domain_get()) diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp index 9f47476ba..0c88c519d 100644 --- a/Source/Engine/Scripting/Runtime/None.cpp +++ b/Source/Engine/Scripting/Runtime/None.cpp @@ -185,6 +185,10 @@ void MCore::GC::WriteArrayRef(MArray* dst, MObject* ref, int32 index) { } +void MCore::GC::WriteArrayRef(MArray* dst, Span refs) +{ +} + void MCore::Thread::Attach() { } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 42609b60b..205cefac3 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -1301,7 +1301,7 @@ namespace Flax.Build.Bindings #pragma warning disable 1591 public static class NativeToManaged { - public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged); + public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged)); public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.NativeToManaged.Free(unmanaged); } public static class ManagedToNative @@ -1316,14 +1316,14 @@ namespace Flax.Build.Bindings public void FromManaged({{classInfo.Name}} managed) => marsh.FromManaged(managed); public IntPtr ToUnmanaged() => marsh.ToUnmanaged(); public void FromUnmanaged(IntPtr unmanaged) => marsh.FromUnmanaged(unmanaged); - public {{classInfo.Name}} ToManaged() => ({{classInfo.Name}})marsh.ToManaged(); + public {{classInfo.Name}} ToManaged() => Unsafe.As<{{classInfo.Name}}>(marsh.ToManaged()); public void Free() => marsh.Free(); } - internal static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})ManagedHandleMarshaller.ConvertToManaged(unmanaged); + internal static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.ConvertToManaged(unmanaged)); internal static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed); internal static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged); - internal static {{classInfo.Name}} ToManaged(IntPtr managed) => ({{classInfo.Name}})ManagedHandleMarshaller.ToManaged(managed); + internal static {{classInfo.Name}} ToManaged(IntPtr managed) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.ToManaged(managed)); internal static IntPtr ToNative({{classInfo.Name}} managed) => ManagedHandleMarshaller.ToNative(managed); #pragma warning restore 1591 } @@ -1504,7 +1504,7 @@ namespace Flax.Build.Bindings if (fieldInfo.Type.IsObjectRef) { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({fieldInfo.Type.GenericArgs[0].Type})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{fieldInfo.Type.GenericArgs[0].Type}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero"); freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); @@ -1513,7 +1513,7 @@ namespace Flax.Build.Bindings } else if (fieldInfo.Type.Type == "ScriptingObject") { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? (FlaxEngine.Object)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero"); freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); @@ -1522,7 +1522,7 @@ namespace Flax.Build.Bindings } else if (fieldInfo.Type.IsPtr && originalType != "IntPtr" && !originalType.EndsWith("*")) { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero"); freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); @@ -1531,7 +1531,7 @@ namespace Flax.Build.Bindings } else if (fieldInfo.Type.Type == "Dictionary") { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); toNativeContent.Append($"ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak)"); freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); @@ -1544,31 +1544,31 @@ namespace Flax.Build.Bindings // Marshal blittable array elements back to original non-blittable elements string originalElementTypeMarshaller = originalElementType + "Marshaller"; string internalElementType = $"{originalElementTypeMarshaller}.{originalElementType}Internal"; - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.NativeArrayToManagedArray<{originalElementType}, {internalElementType}>(((ManagedArray)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).ToSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.NativeArrayToManagedArray<{originalElementType}, {internalElementType}>((Unsafe.As(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target)).ToSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null"); toNativeContent.Append($"ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak)"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = ((ManagedArray)handle.Target).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = ((ManagedArray)handle.Target).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} (Unsafe.As(handle.Target)).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} (Unsafe.As(handle.Target)).Free(); handle.Free(); }}"); } else if (fieldInfo.Type.GenericArgs[0].IsObjectRef) { // Array elements passed as GCHandles - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>((ManagedArray)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>(Unsafe.As(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target)) : null"); toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).ToSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).ToSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = (Unsafe.As(handle.Target)).ToSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As(handle.Target)).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = (Unsafe.As(handle.Target)).ToSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As(handle.Target)).Free(); handle.Free(); }}"); } else { // Blittable array elements - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ((ManagedArray)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).ToArray<{originalElementType}>() : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? (Unsafe.As(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target)).ToArray<{originalElementType}>() : null"); toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As(handle.Target)).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As(handle.Target)).Free(); handle.Free(); }}"); } } else if (fieldInfo.Type.Type == "Version") { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); toNativeContent.Append($"ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak)"); freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");