4 Commits

Author SHA1 Message Date
c7326ea483 _prog
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-12-27 17:59:40 +02:00
523cad3b2c Skip including known non-code subfolders from Source folder 2025-12-27 17:59:33 +02:00
ff6816396c _Formatting flags 2025-12-26 21:49:13 +02:00
24b8ad77fe Fix managed wrapper function parameter handling for BytesContainer 2025-12-23 00:36:57 +02:00
16 changed files with 1625 additions and 282 deletions

View File

@@ -889,6 +889,11 @@ Variant::Variant(const Span<byte>& v)
}
}
Variant::Variant(const BytesContainer& v)
: Variant((const Span<byte>&)(v))
{
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
#include "Engine/Content/Deprecated.h"
Variant::Variant(const CommonValue& value)

View File

@@ -11,6 +11,9 @@ struct CommonValue;
template<typename T>
class AssetReference;
struct ScriptingTypeHandle;
template<typename T>
class DataContainer;
typedef DataContainer<byte> BytesContainer;
/// <summary>
/// Represents an object type that can be interpreted as more than one type.
@@ -244,6 +247,7 @@ public:
explicit Variant(Dictionary<Variant, Variant, HeapAllocation>&& v);
explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v);
explicit Variant(const Span<byte>& v);
explicit Variant(const BytesContainer& v);
explicit Variant(const CommonValue& v);
template<typename T>

View File

@@ -4,7 +4,6 @@
#define USE_GCHANDLE
//#define TRACK_HANDLES
#if USE_NETCORE
using System;
using System.Collections.Generic;

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#if USE_NETCORE
using FlaxEngine.Assertions;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -322,27 +323,24 @@ namespace FlaxEngine.Interop
#if FLAX_EDITOR
[HideInEditor]
#endif
public struct ManagedToNative
public static class ManagedToNative
{
ManagedHandle handle;
public void FromManaged(object[] managed)
public static object[] ConvertToManaged(NativeArray<IntPtr> unmanaged)
{
if (managed != null)
{
var managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
handle = ManagedHandle.Alloc(managedArray, GCHandleType.Weak);
}
if (unmanaged.Data == null)
return null;
return NativeInterop.GCHandleArrayToManagedArray<object>(unmanaged);
}
public IntPtr ToUnmanaged()
public static NativeArray<IntPtr> ConvertToUnmanaged(object[] managed)
{
return ManagedHandle.ToIntPtr(handle);
if (managed == null)
return new NativeArray<IntPtr>();
return NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
}
public void Free()
public static void Free(NativeArray<IntPtr> unmanaged)
{
handle.Free();
if (unmanaged.Data != null)
unmanaged.Free();
}
}
@@ -661,6 +659,431 @@ namespace FlaxEngine.Interop
}
}
#if FLAX_EDITOR
[HideInEditor]
#endif
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(BoxedArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(BoxedArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(BoxedArrayMarshaller<,>))]
[ContiguousCollectionMarshaller]
public static unsafe class BoxedArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class ManagedToNative
{
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
if (managed == null)
{
numElements = 0;
return new NativeArray<TUnmanagedElement>();
}
numElements = managed.Length;
return new NativeArray<TUnmanagedElement>(managed.Length);
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
{
if (managed == null)
return null;
return managed.AsSpan();
}
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
return unmanaged.AsSpan();
}
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
{
if (unmanaged.Data != null)
unmanaged.Free();
}
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class NativeToManaged
{
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
Assert.IsTrue(unmanaged.Length == numElements);
return new T[unmanaged.Length];
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
return unmanaged.AsReadOnlySpan();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
if (managed == null)
return null;
return managed.AsSpan();
}
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
{
if (unmanaged.Data == null)
return;
Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public struct Bidirectional
{
//string managed;
//IntPtr unmanaged;
public void FromManaged(T[] managed)
{
throw new NotImplementedException();
}
public T[] ToManaged()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetManagedValuesSource()
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetManagedValuesDestination(int numElements)
{
throw new NotImplementedException();
}
public NativeArray<TUnmanagedElement> ToUnmanaged()
{
throw new NotImplementedException();
}
public void FromUnmanaged(NativeArray<TUnmanagedElement> unmanaged)
{
throw new NotImplementedException();
}
public void Free()
{
throw new NotImplementedException();
}
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
throw new NotImplementedException();
}
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
{
throw new NotImplementedException();
}
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
[StructLayout(LayoutKind.Sequential)]
public unsafe /*ref*/ struct NativeArray<T> where T : unmanaged
{
public T* Data;
public int Length;
public NativeArray(T* data, int length)
{
Data = data;
Length = length;
}
public NativeArray(Span<T> data)
{
Data = (T*)Marshal.AllocCoTaskMem(data.Length);
Length = data.Length;
for (int i = 0; i < data.Length; i++)
Unsafe.Copy(&Data[i], ref data[i]);
}
public NativeArray(IntPtr data, int length)
{
Data = (T*)data;
Length = length;
}
public NativeArray(int length)
{
Data = (T*)Marshal.AllocCoTaskMem(length);
Length = length;
}
public NativeArray()
{
Data = null;
Length = 0;
}
public void Free() => Marshal.FreeCoTaskMem((IntPtr)Data);
public Span<T> AsSpan() => new Span<T>(Data, Length);
public ReadOnlySpan<T> AsReadOnlySpan() => new Span<T>(Data, Length);
public static bool operator ==(NativeArray<T> left, NativeArray<T> right) => left.Data == right.Data && left.Length == right.Length;
public static bool operator !=(NativeArray<T> left, NativeArray<T> right) => left.Data != right.Data || left.Length != right.Length;
public static bool operator ==(NativeArray<T> left, IntPtr right) => left.Data == (T*)right;
public static bool operator !=(NativeArray<T> left, IntPtr right) => left.Data != (T*)right;
public static bool operator ==(IntPtr left, NativeArray<T> right) => (T*)left == right.Data;
public static bool operator !=(IntPtr left, NativeArray<T> right) => (T*)left != right.Data;
public override bool Equals(object obj)
{
if (obj is null) return false;
if (obj is NativeArray<T> arr) return this == arr;
if (obj is IntPtr ptr) return this == ptr;
return false;
}
public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();
}
#if FLAX_EDITOR
[HideInEditor]
#endif
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeArrayMarshaller<,>))]
[ContiguousCollectionMarshaller]
public static unsafe class NativeArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class ManagedToNative
{
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
public static void Free(NativeArray<TUnmanagedElement> unmanaged) => throw new NotImplementedException();
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class NativeToManaged
{
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return Array.Empty<T>();
Assert.IsTrue(unmanaged.Length == numElements);
return new T[unmanaged.Length];
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
return unmanaged.AsReadOnlySpan();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
if (managed == null)
return null;
return managed.AsSpan();
}
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
{
if (unmanaged.Data == null)
return;
Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public struct Bidirectional
{
//string managed;
//IntPtr unmanaged;
public void FromManaged(T[] managed)
{
throw new NotImplementedException();
}
public T[] ToManaged()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetManagedValuesSource()
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetManagedValuesDestination(int numElements)
{
throw new NotImplementedException();
}
public NativeArray<TUnmanagedElement> ToUnmanaged()
{
throw new NotImplementedException();
}
public void FromUnmanaged(NativeArray<TUnmanagedElement> unmanaged)
{
throw new NotImplementedException();
}
public void Free()
{
throw new NotImplementedException();
}
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
throw new NotImplementedException();
}
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
{
throw new NotImplementedException();
}
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
#if FLAX_EDITOR
[HideInEditor]
#endif

View File

@@ -188,6 +188,28 @@ namespace FlaxEngine.Interop
return Marshal.GetFunctionPointerForDelegate<TDelegate>(d);
}
/// <summary>
/// Converts array of GC Handles from native runtime to managed array.
/// </summary>
/// <typeparam name="T">Array element type.</typeparam>
/// <param name="ptrArray">Input array.</param>
/// <param name="buffer">Cached memory allocation buffer to use for the result (if size fits).</param>
/// <returns>Output array.</returns>
public static T[] GCHandleArrayToManagedArray<T>(NativeArray<IntPtr> ptrArray, T[] buffer = null) where T : class
{
ReadOnlySpan<IntPtr> span = ptrArray.AsReadOnlySpan();
if (buffer != null)
buffer = buffer;
if (buffer == null || buffer.Length < ptrArray.Length)
buffer = new T[ptrArray.Length];
for (int i = 0; i < ptrArray.Length; i++)
{
IntPtr ptr = span[i];
buffer[i] = ptr != IntPtr.Zero ? (T)ManagedHandle.FromIntPtr(ptr).Target : default;
}
return buffer;
}
/// <summary>
/// Converts array of GC Handles from native runtime to managed array.
/// </summary>
@@ -238,6 +260,24 @@ namespace FlaxEngine.Interop
return ManagedArray.WrapNewArray(pointerArray, array.GetType());
}
/// <summary>
/// Converts managed array wrapper into array of GC Handles for native runtime.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Output array.</returns>
public static NativeArray<IntPtr> ManagedArrayToGCHandleWrappedArray<T>(T[] array)
{
NativeArray<IntPtr> pointerArray = new(array.Length);
for (int i = 0; i < array.Length; i++)
//foreach (var ptr in pointerArray.AsSpan())
{
pointerArray.Data[i] = array[i] != null ? ManagedHandle.ToIntPtr(array[i]) : IntPtr.Zero;
}
return pointerArray;
//IntPtr[] pointerArray = ManagedArrayToGCHandleArray(array);
//return ManagedArray.WrapNewArray(pointerArray, array.GetType());
}
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
@@ -270,6 +310,23 @@ namespace FlaxEngine.Interop
return dst;
}
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
/// <typeparam name="TSrc">Input data type.</typeparam>
/// <typeparam name="TDst">Output data type.</typeparam>
/// <param name="src">The input array.</param>
/// <param name="convertFunc">Converter callback.</param>
/// <returns>The output array.</returns>
public static NativeArray<TDst> ConvertArrayNative<TSrc, TDst>(this Span<TSrc> src, Func<TSrc, TDst> convertFunc)
where TDst : unmanaged
{
NativeArray<TDst> dst = new(src.Length);
for (int i = 0; i < src.Length; i++)
dst.Data[i] = convertFunc(src[i]);
return dst;
}
/// <summary>Find <paramref name="assemblyName"/> among the scripting assemblies.</summary>
/// <param name="assemblyName">The name to find</param>
/// <param name="allowPartial">If true, partial names should be allowed to be resolved.</param>
@@ -1140,13 +1197,18 @@ namespace FlaxEngine.Interop
internal static void ToManagedArray(ref T[] managedValue, IntPtr nativePtr, bool byRef)
{
if (byRef)
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
//if (byRef)
// nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
if (nativePtr != IntPtr.Zero)
{
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
var span = new Span<T>(nativePtr.ToPointer(), length);
managedValue = span.ToArray();
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
//managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
}
else
managedValue = null;

View File

@@ -68,13 +68,13 @@ public:
struct FLAXENGINE_API Object
{
static MObject* Box(void* value, const MClass* klass);
static void* Unbox(MObject* obj);
static void Unbox(MObject* obj, void* dest);
static void* Unbox(const MObject* obj);
static void Unbox(const MObject* obj, void* dest);
static MObject* New(const MClass* klass);
static void Init(MObject* obj);
static MClass* GetClass(MObject* obj);
static MString* ToString(MObject* obj);
static int32 GetHashCode(MObject* obj);
static void Init(const MObject* obj);
static MClass* GetClass(const MObject* obj);
static MString* ToString(const MObject* obj);
static int32 GetHashCode(const MObject* obj);
};
/// <summary>
@@ -82,11 +82,11 @@ public:
/// </summary>
struct FLAXENGINE_API String
{
static MString* GetEmpty(MDomain* domain = nullptr);
static MString* New(const char* str, int32 length, MDomain* domain = nullptr);
static MString* New(const Char* str, int32 length, MDomain* domain = nullptr);
static void Free(MString* obj);
static StringView GetChars(MString* obj);
static MString* GetEmpty(const MDomain* domain = nullptr);
static MString* New(const char* str, int32 length, const MDomain* domain = nullptr);
static MString* New(const Char* str, int32 length, const MDomain* domain = nullptr);
static void Free(const MString* obj);
static StringView GetChars(const MString* obj);
};
/// <summary>
@@ -96,11 +96,11 @@ public:
{
static MArray* New(const MClass* elementKlass, int32 length);
static void Free(const MArray* array);
static MClass* GetClass(MClass* elementKlass);
static MClass* GetClass(const MClass* elementKlass);
static MClass* GetArrayClass(const MArray* obj);
static int32 GetLength(const MArray* obj);
static void* GetAddress(const MArray* obj);
static MArray* Unbox(MObject* obj);
static MArray* Unbox(const MObject* obj);
template<typename T>
FORCE_INLINE static T* GetAddress(const MArray* obj)
@@ -114,8 +114,8 @@ public:
/// </summary>
struct FLAXENGINE_API GCHandle
{
static MGCHandle New(MObject* obj, bool pinned = false);
static MGCHandle NewWeak(MObject* obj, bool trackResurrection = false);
static MGCHandle New(const MObject* obj, bool pinned = false);
static MGCHandle NewWeak(const MObject* obj, bool trackResurrection = false);
static MObject* GetTarget(const MGCHandle& handle);
static void Free(const MGCHandle& handle);
};

View File

@@ -106,7 +106,7 @@ public:
/// </remarks>
/// <param name="instance">The object of given type to get value from.</param>
/// <param name="result">The return value of undefined type.</param>
void GetValue(MObject* instance, void* result) const;
void GetValue(const MObject* instance, void* result) const;
/// <summary>
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null.
@@ -116,14 +116,14 @@ public:
/// </remarks>
/// <param name="instance">The object of given type to get value from.</param>
/// <param name="result">The return value of undefined type.</param>
void GetValueReference(MObject* instance, void* result) const;
void GetValueReference(const MObject* instance, void* result) const;
/// <summary>
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed.
/// </summary>
/// <param name="instance">The object of given type to get value from.</param>
/// <returns>The boxed value object.</returns>
MObject* GetValueBoxed(MObject* instance) const;
MObject* GetValueBoxed(const MObject* instance) const;
/// <summary>
/// Sets a value for the field on the specified object instance. If field is static object instance can be null.
@@ -133,7 +133,7 @@ public:
/// </remarks>
/// <param name="instance">The object of given type to set value to.</param>
/// <param name="value">Th value of undefined type.</param>
void SetValue(MObject* instance, void* value) const;
void SetValue(const MObject* instance, void* value) const;
public:
/// <summary>

View File

@@ -13,6 +13,12 @@
#if USE_CSHARP
/*static_assert(TIsPODType<int>::Value, "int not pod type?");
static_assert(TIsPODType<Float3>::Value, "Float3 not pod type?");
static_assert(!TIsPODType<ScriptingObject>::Value, "ScriptingObject not pod type?");
static_assert(TIsPODType<Char>::Value, "Char not pod type?");
static_assert(TIsPODType<char>::Value, "char not pod type?");*/
struct Version;
class CultureInfo;
template<typename AllocationType>
@@ -49,6 +55,12 @@ struct MConverter
{
MObject* Box(const T& data, const MClass* klass);
void Unbox(T& result, MObject* data);
/*template<typename U>
void ToManaged(U& result, const T& data);
template<typename U>
void ToNative(T& result, const U& data);
void ToManaged(MObject*& result, const T& data);
void ToNative(T& result, const MObject*& data);*/
void FreeManaged(MObject* data);
void ToManagedArray(MArray* result, const Span<T>& data);
void ToNativeArray(Span<T>& result, const MArray* data);
@@ -61,6 +73,16 @@ struct NativeArray
{
T* data;
int32 length;
FORCE_INLINE operator T*() const
{
return data;
}
FORCE_INLINE Span<T> ToSpan() const
{
return Span<T>(data, length);
}
};
#if USE_NETCORE
@@ -79,6 +101,16 @@ struct MConverter<bool>
MCore::Object::Unbox(data, &result);
}
void ToManaged(bool& result, const bool& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(bool& result, const bool& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManaged(MObject* data)
{
}
@@ -116,6 +148,16 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
MCore::Object::Unbox(data, &result);
}
void ToManaged(T& result, const T& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(T& result, const T& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<T>& data)
{
Platform::MemoryCopy(MCore::Array::GetAddress(result), data.Get(), data.Length() * sizeof(T));
@@ -162,6 +204,16 @@ struct MConverter<String>
//#endif
}
void ToManaged(String& result, const String& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(String& result, const String& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<String>& data)
{
if (data.Length() == 0)
@@ -212,6 +264,16 @@ struct MConverter<StringAnsi>
result = MUtils::ToStringAnsi((MString*)data);
}
void ToManaged(StringAnsi& result, const StringAnsi& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(StringAnsi& result, const StringAnsi& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<StringAnsi>& data)
{
if (data.Length() == 0)
@@ -262,6 +324,16 @@ struct MConverter<StringView>
result = MUtils::ToString((MString*)data);
}
void ToManaged(StringView& result, const StringView& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(StringView& result, const StringView& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<StringView>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -316,6 +388,16 @@ struct MConverter<Variant>
result = MUtils::UnboxVariant(data);
}
void ToManaged(Variant& result, const Variant& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(Variant& result, const Variant& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<Variant>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -365,6 +447,18 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
result = (T*)ScriptingObject::ToNative(data);
}
void ToManaged(MObject*& result, const T* data)
{
//PLATFORM_DEBUG_BREAK; // FIXME
result = data ? data->GetOrCreateManagedInstance() : nullptr;
}
void ToNative(T*& result, const MObject* data)
{
PLATFORM_DEBUG_BREAK; // FIXME
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MArray* result, const Span<T*>& data)
{
if (data.Length() == 0)
@@ -405,9 +499,29 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
return data.GetOrCreateManagedInstance();
}
void ToManagedArray(MArray* result, const Span<T>& data)
void ToManaged(MObject*& result, const T& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(T& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
/*void ToManaged(MObject*& result, const T*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(T*& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}*/
void ToManagedArray(MArray* result, const Span<T>& data)
{
//PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0)
return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -449,6 +563,16 @@ struct MConverter<ScriptingObjectReference<T>>
result = (T*)ScriptingObject::ToNative(data);
}
void ToManaged(MObject*& result, const ScriptingObjectReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(ScriptingObjectReference<T>& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -501,6 +625,17 @@ struct MConverter<AssetReference<T>>
result = (T*)ScriptingObject::ToNative(data);
}
void ToManaged(MObject*& result, const AssetReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
result = data.GetManagedInstance();
}
void ToNative(AssetReference<T>& result, const MObject* data)
{
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MArray* result, const Span<AssetReference<T>>& data)
{
if (data.Length() == 0)
@@ -538,6 +673,29 @@ class SoftAssetReference;
template<typename T>
struct MConverter<SoftAssetReference<T>>
{
template <typename U>
void ToManaged(U& result, const SoftAssetReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
template <typename U>
void ToNative(SoftAssetReference<T>& result, const U& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManaged(MObject*& result, const SoftAssetReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(SoftAssetReference<T>& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<SoftAssetReference<T>>& data)
{
//PLATFORM_DEBUG_BREAK; // FIXME
@@ -575,6 +733,16 @@ struct MConverter<SoftAssetReference<T>>
template<typename T>
struct MConverter<Array<T>>
{
void ToManaged(Array<T>& result, const Array<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(Array<T>& result, const Array<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
MObject* Box(const Array<T>& data, const MClass* klass)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -877,12 +1045,36 @@ namespace MUtils
return arr;
}
/// <summary>
/// Allocates new managed array of data and copies contents from given native array.
/// </summary>
/// <param name="data">The array object.</param>
/// <param name="valueClass">The array values type class.</param>
/// <returns>The output array.</returns>
/*template<typename T, typename U>
NativeArray<U> ToManagedArrayWrapper(const Span<T>& data, const MClass* valueClass)
{
if (!valueClass)
return nullptr;
MArray* result = MCore::Array::New(valueClass, data.Length());
MConverter<T> converter;
converter.ToManagedArray(result, data);
return result;
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Count();
arr.data = (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true);
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(U));
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename AllocationType = HeapAllocation>
/*template<typename T, typename AllocationType = HeapAllocation>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
@@ -893,22 +1085,233 @@ namespace MUtils
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename U, typename AllocationType = HeapAllocation>
FORCE_INLINE NativeArray<U> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Count();
arr.data = (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true);
// Convert to managed
MConverter<T, U> converter;
for (int i = 0; i < arr.length; ++i)
arr.data[i] = converter.ToManaged(data[i]);
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename U>
FORCE_INLINE NativeArray<U> ToManagedArrayWrapperConvert(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true) : nullptr;
// Convert to managed
MConverter<T, U> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToManaged(arr.data[i], data[i]);
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Span<T>& data)
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperConvertGeneric(const Span<MObject*>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true);
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
// Convert to managed
MConverter<T> converter;
for (int i = 0; i < arr.length; ++i)
{
converter.ToNative(arr.data[i], data[i]);
}
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename AllocationType = HeapAllocation>
FORCE_INLINE void ToNativeArrayWrapperConvertGeneric(const Span<MObject*>& data, Array<T, AllocationType>& array)
{
if (!array.IsEmpty())
PLATFORM_DEBUG_BREAK; // TODO: does the array require ClearDelete instead?
auto length = data.Length();
array.Resize(length, false);
//array.Clear();
//array.EnsureCapacity(length);
MConverter<T> converter;
for (int i = 0; i < length; ++i)
{
// Make sure the destination is default initialized first
//array.AddUninitialized();
//array.AddDefault();
//T& dest = array.Get()[i];
//new(&dest)AssetReference<T>();
// Convert from managed
converter.ToNative(array.Get()[i], data[i]);
}
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename U>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperConvert(const Span<U>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
// Convert to managed
MConverter<T, U> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToNative(arr.data[i], data[i]);
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperCopy(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
/*FORCE_INLINE NativeArray<Char> ToManagedArrayWrapper(const Span<Char>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<Char> arr;
arr.length = data.Length();
arr.data = (Char*)MCore::GC::AllocateMemory(arr.length * sizeof(Char), true);
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(Char));
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToManagedArrayWrapperConvert(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
//Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
// Convert to managed
MConverter<T> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToManaged(arr.data[i], data[i]);
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToManagedArrayWrapperCopy(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
/*template<typename T>
FORCE_INLINE NativeArray<MObject*> ToManagedArrayWrapperPointer(const Span<T*>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<MObject*> arr;
arr.length = data.Length();
arr.data = (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true);
// Convert to managed
MConverter<T*> converter;
for (int i = 0; i < arr.length; ++i)
{
MObject*& ptr = arr.data[i];
const T& asd = data[i];
converter.ToManaged(ptr, asd);
}
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<class T>
FORCE_INLINE NativeArray<MObject*> ToManagedArrayWrapperPointer(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<MObject*> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true) : nullptr;
// Convert to managed
MConverter<T> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToManaged(arr.data[i], data[i]);
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>

View File

@@ -399,15 +399,15 @@ MObject* MCore::Object::Box(void* value, const MClass* klass)
return (MObject*)CallStaticMethod<void*, void*, void*>(BoxValuePtr, klass->_handle, value);
}
void* MCore::Object::Unbox(MObject* obj)
void* MCore::Object::Unbox(const MObject* obj)
{
CRASH; // Should not be used anymore
}
void MCore::Object::Unbox(MObject* obj, void* dest)
void MCore::Object::Unbox(const MObject* obj, void* dest)
{
static void* UnboxValuePtr = GetStaticMethodPointer(TEXT("UnboxValue"));
return CallStaticMethod<void, void*, void*>(UnboxValuePtr, obj, dest);
return CallStaticMethod<void, const void*, void*>(UnboxValuePtr, obj, dest);
}
MObject* MCore::Object::New(const MClass* klass)
@@ -416,61 +416,61 @@ MObject* MCore::Object::New(const MClass* klass)
return (MObject*)CallStaticMethod<void*, void*>(NewObjectPtr, klass->_handle);
}
void MCore::Object::Init(MObject* obj)
void MCore::Object::Init(const MObject* obj)
{
static void* ObjectInitPtr = GetStaticMethodPointer(TEXT("ObjectInit"));
CallStaticMethod<void, void*>(ObjectInitPtr, obj);
CallStaticMethod<void, const void*>(ObjectInitPtr, obj);
}
MClass* MCore::Object::GetClass(MObject* obj)
MClass* MCore::Object::GetClass(const MObject* obj)
{
ASSERT(obj);
static void* GetObjectClassPtr = GetStaticMethodPointer(TEXT("GetObjectClass"));
return (MClass*)CallStaticMethod<MClass*, void*>(GetObjectClassPtr, obj);
return (MClass*)CallStaticMethod<MClass*, const void*>(GetObjectClassPtr, obj);
}
MString* MCore::Object::ToString(MObject* obj)
MString* MCore::Object::ToString(const MObject* obj)
{
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectString"));
return (MString*)CallStaticMethod<void*, void*>(GetObjectStringPtr, obj);
return (MString*)CallStaticMethod<void*, const void*>(GetObjectStringPtr, obj);
}
int32 MCore::Object::GetHashCode(MObject* obj)
int32 MCore::Object::GetHashCode(const MObject* obj)
{
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectHashCode"));
return CallStaticMethod<int32, void*>(GetObjectStringPtr, obj);
return CallStaticMethod<int32, const void*>(GetObjectStringPtr, obj);
}
MString* MCore::String::GetEmpty(MDomain* domain)
MString* MCore::String::GetEmpty(const MDomain* domain)
{
static void* GetStringEmptyPtr = GetStaticMethodPointer(TEXT("GetStringEmpty"));
return (MString*)CallStaticMethod<void*>(GetStringEmptyPtr);
}
MString* MCore::String::New(const char* str, int32 length, MDomain* domain)
MString* MCore::String::New(const char* str, int32 length, const MDomain* domain)
{
static void* NewStringUTF8Ptr = GetStaticMethodPointer(TEXT("NewStringUTF8"));
return (MString*)CallStaticMethod<void*, const char*, int>(NewStringUTF8Ptr, str, length);
}
MString* MCore::String::New(const Char* str, int32 length, MDomain* domain)
MString* MCore::String::New(const Char* str, int32 length, const MDomain* domain)
{
static void* NewStringUTF16Ptr = GetStaticMethodPointer(TEXT("NewStringUTF16"));
return (MString*)CallStaticMethod<void*, const Char*, int>(NewStringUTF16Ptr, str, length);
}
StringView MCore::String::GetChars(MString* obj)
StringView MCore::String::GetChars(const MString* obj)
{
int32 length = 0;
static void* GetStringPointerPtr = GetStaticMethodPointer(TEXT("GetStringPointer"));
const Char* chars = CallStaticMethod<const Char*, void*, int*>(GetStringPointerPtr, obj, &length);
const Char* chars = CallStaticMethod<const Char*, const void*, int*>(GetStringPointerPtr, obj, &length);
return StringView(chars, length);
}
void MCore::String::Free(MString* obj)
void MCore::String::Free(const MString* obj)
{
static void* FreeStringPtr = GetStaticMethodPointer(TEXT("FreeString"));
CallStaticMethod<void, void*>(FreeStringPtr, obj);
CallStaticMethod<void, const void*>(FreeStringPtr, obj);
}
MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
@@ -485,7 +485,7 @@ void MCore::Array::Free(const MArray* array)
CallStaticMethod<void, void*>(FreeArrayPtr, (void*)array);
}
MClass* MCore::Array::GetClass(MClass* elementKlass)
MClass* MCore::Array::GetClass(const MClass* elementKlass)
{
static void* GetArrayTypeFromElementTypePtr = GetStaticMethodPointer(TEXT("GetArrayTypeFromElementType"));
MType* typeHandle = (MType*)CallStaticMethod<void*, void*>(GetArrayTypeFromElementTypePtr, elementKlass->_handle);
@@ -511,24 +511,24 @@ void* MCore::Array::GetAddress(const MArray* obj)
return CallStaticMethod<void*, void*>(GetArrayPointerPtr, (void*)obj);
}
MArray* MCore::Array::Unbox(MObject* obj)
MArray* MCore::Array::Unbox(const MObject* obj)
{
static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray"));
return (MArray*)CallStaticMethod<void*, void*>(GetArrayPtr, (void*)obj);
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
MGCHandle MCore::GCHandle::New(const MObject* obj, bool pinned)
{
ASSERT(obj);
static void* NewGCHandlePtr = GetStaticMethodPointer(TEXT("NewGCHandle"));
return (MGCHandle)CallStaticMethod<void*, void*, bool>(NewGCHandlePtr, obj, pinned);
return (MGCHandle)CallStaticMethod<void*, const void*, bool>(NewGCHandlePtr, obj, pinned);
}
MGCHandle MCore::GCHandle::NewWeak(MObject* obj, bool trackResurrection)
MGCHandle MCore::GCHandle::NewWeak(const MObject* obj, bool trackResurrection)
{
ASSERT(obj);
static void* NewGCHandleWeakPtr = GetStaticMethodPointer(TEXT("NewGCHandleWeak"));
return (MGCHandle)CallStaticMethod<void*, void*, bool>(NewGCHandleWeakPtr, obj, trackResurrection);
return (MGCHandle)CallStaticMethod<void*, const void*, bool>(NewGCHandleWeakPtr, obj, trackResurrection);
}
MObject* MCore::GCHandle::GetTarget(const MGCHandle& handle)
@@ -1387,28 +1387,28 @@ int32 MField::GetOffset() const
return _fieldOffset;
}
void MField::GetValue(MObject* instance, void* result) const
void MField::GetValue(const MObject* instance, void* result) const
{
static void* FieldGetValuePtr = GetStaticMethodPointer(TEXT("FieldGetValue"));
CallStaticMethod<void, void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
CallStaticMethod<void, const void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
}
void MField::GetValueReference(MObject* instance, void* result) const
void MField::GetValueReference(const MObject* instance, void* result) const
{
static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReference"));
CallStaticMethod<void, void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result);
CallStaticMethod<void, const void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result);
}
MObject* MField::GetValueBoxed(MObject* instance) const
MObject* MField::GetValueBoxed(const MObject* instance) const
{
static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed"));
return CallStaticMethod<MObject*, void*, void*>(FieldGetValueBoxedPtr, instance, _handle);
return CallStaticMethod<MObject*, const void*, void*>(FieldGetValueBoxedPtr, instance, _handle);
}
void MField::SetValue(MObject* instance, void* value) const
void MField::SetValue(const MObject* instance, void* value) const
{
static void* FieldSetValuePtr = GetStaticMethodPointer(TEXT("FieldSetValue"));
CallStaticMethod<void, void*, void*, void*>(FieldSetValuePtr, instance, _handle, value);
CallStaticMethod<void, const void*, void*, void*>(FieldSetValuePtr, instance, _handle, value);
}
bool MField::HasAttribute(const MClass* klass) const

View File

@@ -245,7 +245,7 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
return result;
}
ScriptingObject* ScriptingObject::ToNative(MObject* obj)
ScriptingObject* ScriptingObject::ToNative(const MObject* obj)
{
ScriptingObject* ptr = nullptr;
#if USE_CSHARP

View File

@@ -132,7 +132,7 @@ public:
return (T*)ToInterface(obj, T::TypeInitializer);
}
static ScriptingObject* ToNative(MObject* obj);
static ScriptingObject* ToNative(const MObject* obj);
FORCE_INLINE static MObject* ToManaged(const ScriptingObject* obj)
{

View File

@@ -635,44 +635,60 @@ namespace Flax.Build.Bindings
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (functionInfo.ReturnType.IsArrayOrSpan || returnNativeType == "Array")
{
var elementApiType = functionInfo.ReturnType.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, functionInfo.ReturnType.GenericArgs[0], caller) : null;
string unmanagedType = "";
if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller))
//if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller))
var genericType = functionInfo.ReturnType.GenericArgs?[0].Type;
if (functionInfo.ReturnType.Type == "BytesContainer")
genericType = "byte";
if (functionInfo.ReturnType.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
genericType = null;
switch (genericType)
{
switch (functionInfo.ReturnType.GenericArgs[0].Type)
{
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
default:
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
case null:
case "":
case "String":
case "StringAnsi":
case "StringView":
unmanagedType = null;
break;
default:
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
unmanagedType = null;
else
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
if (!string.IsNullOrEmpty(unmanagedType))
{
@@ -681,18 +697,22 @@ namespace Flax.Build.Bindings
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
returnMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__returnCount"))})";
}
else if (genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
returnMarshalType = $"/*marsh2c*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<string, IntPtr>), CountElementName = \"__returnCount\")";
else if (elementApiType?.IsValueType ?? true)
returnMarshalType = $"/*marsh2a*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__returnCount\")";
else
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
returnMarshalType = $"/*marsh2b*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__returnCount\")";
}
else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array")
{
//[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 8)]
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
returnMarshalType = "/*marsh3*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
}
else if (functionInfo.ReturnType.Type == "Dictionary")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (returnValueType == "byte[]")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
returnMarshalType = "/*marsh4*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__returnCount\")";
else if (returnValueType == "bool[]")
{
// Boolean arrays does not support custom marshalling for some unknown reason
@@ -742,44 +762,65 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (parameterInfo.Type.IsArrayOrSpan || nativeType == "Array")
{
var elementApiType = parameterInfo.Type.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
string unmanagedType = "";
if (parameterInfo.Type.GenericArgs != null && parameterInfo.Type.GenericArgs[0].IsPod(buildData, caller))
var genericType = parameterInfo.Type.GenericArgs?[0].Type;
if (parameterInfo.Type.Type == "BytesContainer")
genericType = "byte";
if (parameterInfo.Type.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
genericType = null;
switch (genericType)
{
switch (parameterInfo.Type.GenericArgs[0].Type)
{
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
default:
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
case null:
case "":
case "String":
case "StringAnsi":
case "StringView":
unmanagedType = null;
break;
case "AntiRollBar":
unmanagedType = "Any"; // FIXME: This looks like a POD-type but isn't one?
break;
default:
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
unmanagedType = null;
else if (elementApiType == null)
unmanagedType = "Any";
else
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
if (!string.IsNullOrEmpty(unmanagedType))
{
@@ -788,10 +829,28 @@ namespace Flax.Build.Bindings
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__{parameterInfo.Name}Count"))})";
}
else if (genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
parameterMarshalType = $"/*marsh5c*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<string, IntPtr>), CountElementName = \"__{parameterInfo.Name}Count\")";
else if (elementApiType.IsValueType)
{
var nativeName = parameterInfo.Type.GetFullNameNative(buildData, caller);
var nativeInternalName = GenerateCppManagedWrapperName(elementApiType);
var marshallerName = (!string.IsNullOrEmpty(elementApiType?.Namespace) ? $"{elementApiType?.Namespace}.Interop." : "") + $"{elementApiType.Name}Marshaller";
//parameterMarshalType = $"/*marsh5a pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
if (/*nativeName != nativeInternalName && */elementApiType.MarshalAs != null)
parameterMarshalType = $"/*marsh5a1 pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
else
parameterMarshalType = $"/*marsh5a2 pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<{elementApiType.Name},{marshallerName}.{elementApiType.Name}Internal>), CountElementName = \"__{parameterInfo.Name}Count\")";
//parameterMarshalType += $"] [MarshalUsing(typeof({marshallerName}), ElementIndirectionDepth = 1)";
// [MarshalUsing(typeof(ExampleMarshaller), ElementIndirectionDepth = 1)]
}
else
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
parameterMarshalType = $"/*marsh5b*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
if (!parameterInfo.IsOut && !parameterInfo.IsRef)
parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters.
//if (elementApiType?.MarshalAs != null)
// parameterMarshalType += $"] [MarshalUsing(typeof({elementApiType.MarshalAs}), ElementIndirectionDepth = 1)";
}
else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
@@ -801,7 +860,7 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalAs(UnmanagedType.I2)";
else if (nativeType.EndsWith("[]"))
{
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>))";
parameterMarshalType = $"/*marsh6*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>))";
}
if (!string.IsNullOrEmpty(parameterMarshalType))
@@ -841,7 +900,7 @@ namespace Flax.Build.Bindings
{
// TODO: make this code shared with MarshalUsing selection from the above
if (parameterInfo.Type.IsArrayOrSpan)
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
parameterMarshalType = $"/*marsh1*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (parameterInfo.Type.Type == "CultureInfo")
@@ -1806,11 +1865,22 @@ namespace Flax.Build.Bindings
type = "IntPtr";
else if (marshalType.IsPtr && !originalType.EndsWith("*"))
type = "IntPtr";
else if (marshalType.Type == "Array" || marshalType.Type == "Span" || marshalType.Type == "DataContainer" || marshalType.Type == "BytesContainer")
else if (marshalType.IsArrayOrSpan)
{
type = "IntPtr";
apiType = FindApiTypeInfo(buildData, marshalType.GenericArgs[0], structureInfo);
internalType = apiType is StructureInfo elementStructureInfo && UseCustomMarshalling(buildData, elementStructureInfo, structureInfo);
string originalElementType = originalType.Substring(0, originalType.Length - 2);
if (internalType)
{
string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller";
string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal";
type = $"NativeArray<{internalElementType}>";
}
else if (marshalType.GenericArgs[0].IsObjectRef)
type = "NativeArray<IntPtr>";
else
type = $"NativeArray<{originalElementType}>";
}
else if (marshalType.Type == "Version")
type = "IntPtr";
@@ -1827,12 +1897,14 @@ namespace Flax.Build.Bindings
}
//else if (type == "Guid")
// type = "GuidNative";
structContents.Append($"{type} {fieldInfo.Name};").Append(type == "IntPtr" ? $" // {originalType}" : "").AppendLine();
structContents.Append($"{type} {fieldInfo.Name};").Append(type != originalType ? $" // {originalType}" : "").AppendLine();
}
// Generate struct constructor/getter and deconstructor/setter function
toManagedContent.Append("managed.").Append(fieldInfo.Name).Append(" = ");
toNativeContent.Append("unmanaged.").Append(fieldInfo.Name).Append(" = ");
var managedField = $"managed.{fieldInfo.Name}";
var unmanagedField = $"unmanaged.{fieldInfo.Name}";
toManagedContent.Append($"{managedField} = ");
toNativeContent.Append($"{unmanagedField} = ");
if (marshalType.IsObjectRef)
{
var managedType = GenerateCSharpNativeToManaged(buildData, marshalType.GenericArgs[0], structureInfo);
@@ -1868,7 +1940,7 @@ namespace Flax.Build.Bindings
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(); }}");
}
else if (marshalType.Type == "Array" || marshalType.Type == "Span" || marshalType.Type == "DataContainer" || marshalType.Type == "BytesContainer")
else if (marshalType.IsArrayOrSpan)
{
string originalElementType = originalType.Substring(0, originalType.Length - 2);
if (internalType)
@@ -1877,17 +1949,17 @@ namespace Flax.Build.Bindings
string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller";
string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal";
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.ConvertArray((Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(NativeInterop.ConvertArray(managed.{fieldInfo.Name}, {originalElementTypeMarshaller}.ToNative)), GCHandleType.Weak) : IntPtr.Zero;");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} (Unsafe.As<ManagedArray>(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<ManagedArray>(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.NativeToManaged.Free(value); }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.ConvertArray({unmanagedField}.AsSpan(), {originalElementTypeMarshaller}.ToManaged) : null;");
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ConvertArrayNative({managedField}.AsSpan(), {originalElementTypeMarshaller}.ToNative) : new NativeArray<{internalElementType}>();");
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.Free(value); }} {unmanagedField}.Free(); }}");
freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.NativeToManaged.Free(value); }} {unmanagedField}.Free(); }}");
}
else if (marshalType.GenericArgs[0].IsObjectRef)
{
// Array elements passed as GCHandles
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>(Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)) : null;");
toNativeContent.AppendLine($"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<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>({unmanagedField}) : null;");
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name}) : new NativeArray<IntPtr>();");
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var ptr in {unmanagedField}.AsReadOnlySpan()) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} {unmanagedField}.Free(); }}");
// Permanent ScriptingObject handle is passed from native side, do not release it
//freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
@@ -1895,10 +1967,10 @@ namespace Flax.Build.Bindings
else
{
// Blittable array elements
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? (Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToArray<{originalElementType}>() : null;");
toNativeContent.AppendLine($"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}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? {unmanagedField}.AsReadOnlySpan().ToArray() : null;");
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? new NativeArray<{originalElementType}>({managedField}.AsSpan()) : new NativeArray<{originalElementType}>();");
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
}
}
else if (marshalType.Type == "Version")

File diff suppressed because it is too large Load Diff

View File

@@ -487,6 +487,10 @@ namespace Flax.Build.Platforms
}
commonArgs.Add("/Zc:__cplusplus");
// Strict standards conformance mode
commonArgs.Add("/permissive-");
commonArgs.Add("/Zc:externC-"); // Required for WindowsMinimal.h
// Generate Intrinsic Functions
if (compileEnvironment.IntrinsicFunctions)
commonArgs.Add("/Oi");

View File

@@ -204,7 +204,7 @@ namespace Flax.Build.Projects.VisualStudio
var filePath = file.Replace('/', '\\'); // Normalize path
var projectPath = Utilities.MakePathRelativeTo(filePath, projectDirectory);
string linkPath = null;
if (!filePath.StartsWith(rootPath))
if (!filePath.StartsWith(rootPath)) // TODO: FIXME for FlaxEngine project in game solutions
{
// Create folder structure for project external files
var sourceIndex = filePath.LastIndexOf(@"\Source\");

View File

@@ -233,9 +233,17 @@ namespace Flax.Build.Projects.VisualStudio
files.AddRange(project.SourceFiles);
if (project.SourceDirectories != null)
{
foreach (var folder in project.SourceDirectories)
foreach (var sourceDirectory in project.SourceDirectories)
{
files.AddRange(Directory.GetFiles(folder, "*", SearchOption.AllDirectories));
var subDirectories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (var directory in subDirectories)
{
// Skip common non-source directories
if (directory == "obj" || directory == "Properties")
continue;
files.AddRange(Directory.GetFiles(directory, "*", SearchOption.AllDirectories));
}
}
}