Fixes for Visual Scripting interop via C# on new dotnet7 hosting

This commit is contained in:
Wojtek Figat
2023-03-28 12:01:55 +02:00
parent ed13de2d5b
commit 0694f87b0d
7 changed files with 106 additions and 71 deletions

View File

@@ -2857,6 +2857,29 @@ namespace FlaxEngine
valueHandle.Free();
}
[UnmanagedCallersOnly]
internal static ManagedHandle GetTypeClass(ManagedHandle typeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
if (type.IsByRef)
type = type.GetElementType(); // Drop reference type (&) to get actual value type
return GetTypeGCHandle(type);
}
[UnmanagedCallersOnly]
internal static bool GetTypeIsPointer(ManagedHandle typeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
return type.IsPointer;
}
[UnmanagedCallersOnly]
internal static bool GetTypeIsReference(ManagedHandle typeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
return type.IsByRef;
}
internal enum MTypes : uint
{
End = 0x00,
@@ -2901,6 +2924,8 @@ namespace FlaxEngine
internal static uint GetTypeMTypesEnum(ManagedHandle typeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
if (type.IsByRef)
type = type.GetElementType(); // Drop reference type (&) to get actual value type
MTypes monoType;
switch (type)
{
@@ -2943,24 +2968,8 @@ namespace FlaxEngine
monoType = MTypes.Ptr;
break;
case Type _ when type.IsEnum:
{
var elementType = type.GetEnumUnderlyingType();
if (elementType == typeof(sbyte) || elementType == typeof(short))
monoType = MTypes.I2;
else if (elementType == typeof(byte) || elementType == typeof(ushort))
monoType = MTypes.U2;
else if (elementType == typeof(int))
monoType = MTypes.I4;
else if (elementType == typeof(uint))
monoType = MTypes.U4;
else if (elementType == typeof(long))
monoType = MTypes.I8;
else if (elementType == typeof(ulong))
monoType = MTypes.U8;
else
throw new Exception($"Unsupported type '{type.FullName}'");
monoType = MTypes.Enum;
break;
}
case Type _ when type.IsArray:
case Type _ when type == typeof(ManagedArray):
monoType = MTypes.Array;

View File

@@ -250,7 +250,7 @@ namespace FlaxEngine
deleg(instancePtr.Target, ref param1);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
return IntPtr.Zero;
}
@@ -299,8 +299,8 @@ namespace FlaxEngine
deleg(instancePtr.Target, ref param1, ref param2);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
return IntPtr.Zero;
}
@@ -353,9 +353,9 @@ namespace FlaxEngine
deleg(instancePtr.Target, ref param1, ref param2, ref param3);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
return IntPtr.Zero;
}
@@ -412,10 +412,10 @@ namespace FlaxEngine
deleg(instancePtr.Target, ref param1, ref param2, ref param3, ref param4);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param4Ptr != IntPtr.Zero && types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
return IntPtr.Zero;
}
@@ -500,7 +500,7 @@ namespace FlaxEngine
deleg(ref param1);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
return IntPtr.Zero;
}
@@ -549,8 +549,8 @@ namespace FlaxEngine
deleg(ref param1, ref param2);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
return IntPtr.Zero;
}
@@ -603,9 +603,9 @@ namespace FlaxEngine
deleg(ref param1, ref param2, ref param3);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
return IntPtr.Zero;
}
@@ -662,10 +662,10 @@ namespace FlaxEngine
deleg(ref param1, ref param2, ref param3, ref param4);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param4Ptr != IntPtr.Zero && types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
return IntPtr.Zero;
}
@@ -750,7 +750,7 @@ namespace FlaxEngine
TRet ret = deleg(instancePtr.Target, ref param1);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
return MarshalReturnValue(ref ret);
}
@@ -799,8 +799,8 @@ namespace FlaxEngine
TRet ret = deleg(instancePtr.Target, ref param1, ref param2);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
return MarshalReturnValue(ref ret);
}
@@ -853,9 +853,9 @@ namespace FlaxEngine
TRet ret = deleg(instancePtr.Target, ref param1, ref param2, ref param3);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
return MarshalReturnValue(ref ret);
}
@@ -912,10 +912,10 @@ namespace FlaxEngine
TRet ret = deleg(instancePtr.Target, ref param1, ref param2, ref param3, ref param4);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param4Ptr != IntPtr.Zero && types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
return MarshalReturnValue(ref ret);
}
@@ -1000,7 +1000,7 @@ namespace FlaxEngine
TRet ret = deleg(ref param1);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
return MarshalReturnValue(ref ret);
}
@@ -1049,8 +1049,8 @@ namespace FlaxEngine
TRet ret = deleg(ref param1, ref param2);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
return MarshalReturnValue(ref ret);
}
@@ -1103,9 +1103,9 @@ namespace FlaxEngine
TRet ret = deleg(ref param1, ref param2, ref param3);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
return MarshalReturnValue(ref ret);
}
@@ -1162,10 +1162,10 @@ namespace FlaxEngine
TRet ret = deleg(ref param1, ref param2, ref param3, ref param4);
// Marshal reference parameters back to original unmanaged references
if (types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
if (param1Ptr != IntPtr.Zero && types[0].IsByRef) MarshalHelper<T1>.ToNative(ref param1, param1Ptr);
if (param2Ptr != IntPtr.Zero && types[1].IsByRef) MarshalHelper<T2>.ToNative(ref param2, param2Ptr);
if (param3Ptr != IntPtr.Zero && types[2].IsByRef) MarshalHelper<T3>.ToNative(ref param3, param3Ptr);
if (param4Ptr != IntPtr.Zero && types[3].IsByRef) MarshalHelper<T4>.ToNative(ref param4, param4Ptr);
return MarshalReturnValue(ref ret);
}

View File

@@ -798,10 +798,11 @@ namespace
return nullptr;
}
bool VariantTypeEquals(const VariantType& type, MType* mType)
bool VariantTypeEquals(const VariantType& type, MType* mType, bool isOut = false)
{
MClass* mClass = MCore::Type::GetClass(mType);
if (MUtils::GetClass(type) != mClass)
MClass* variantClass = MUtils::GetClass(type);
if (variantClass != mClass)
{
// Hack for Vector2/3/4 which alias with Float2/3/4 or Double2/3/4 (depending on USE_LARGE_WORLDS)
const auto& stdTypes = *StdTypesContainer::Instance();
@@ -840,7 +841,7 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
auto& param = signature.Params[paramIdx];
MType* type = method->GetParameterType(paramIdx);
if (param.IsOut != method->GetParameterIsOut(paramIdx) ||
!VariantTypeEquals(param.Type, type))
!VariantTypeEquals(param.Type, type, param.IsOut))
{
isValid = false;
break;
@@ -1289,8 +1290,8 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
if (paramTypeHandle)
{
auto& valueType = paramTypeHandle.GetType();
MISSING_CODE("TODO: reimplement unpacking managed structure out parameter from C# call");
//valueType.Struct.Unbox(paramValue.AsBlob.Data, (MObject*)((byte*)param - sizeof(MonoObject))); // TODO: fix this for dotnet7
MObject* boxed = MCore::Object::Box(param, valueType.ManagedClass);
valueType.Struct.Unbox(paramValue.AsBlob.Data, boxed);
}
break;
}

View File

@@ -147,6 +147,7 @@ public:
{
static ::String ToString(MType* type);
static MClass* GetClass(MType* type);
static MType* GetElementType(MType* type);
static int32 GetSize(MType* type);
static MTypes GetType(MType* type);
static bool IsPointer(MType* type);

View File

@@ -1166,6 +1166,12 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, MType* type, bool& failed)
}
}
break;
case MTypes::Enum:
{
if (value.Type.Type != VariantType::Enum)
return nullptr;
return &value.AsUint64;
}
case MTypes::Class:
{
if (value.Type.Type == VariantType::Null)
@@ -1183,7 +1189,8 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, MType* type, bool& failed)
if (value.Type.Type != VariantType::Array)
return nullptr;
MObject* object = BoxVariant(value);
if (object && !MCore::Object::GetClass(object)->IsSubClassOf(MCore::Array::GetClass(MCore::Type::GetClass(type))))
auto typeStr = MCore::Type::ToString(type);
if (object && !MCore::Object::GetClass(object)->IsSubClassOf(MCore::Type::GetClass(type)))
object = nullptr;
return object;
}

View File

@@ -525,9 +525,17 @@ MObject* MCore::Exception::GetNotSupported(const char* msg)
MClass* MCore::Type::GetClass(MType* type)
{
static void* GetTypeClassPtr = GetStaticMethodPointer(TEXT("GetTypeClass"));
type = (MType*)CallStaticMethod<void*, void*>(GetTypeClassPtr, type);
return GetOrCreateClass(type);
}
MType* MCore::Type::GetElementType(MType* type)
{
static void* GetElementClassPtr = GetStaticMethodPointer(TEXT("GetElementClass"));
return (MType*)CallStaticMethod<void*, void*>(GetElementClassPtr, type);
}
int32 MCore::Type::GetSize(MType* type)
{
return GetOrCreateClass(type)->GetInstanceSize();
@@ -546,14 +554,14 @@ MTypes MCore::Type::GetType(MType* type)
bool MCore::Type::IsPointer(MType* type)
{
MISSING_CODE("TODO: MCore::Type::IsPointer"); // TODO: MCore::Type::IsPointer
return false;
static void* GetTypeIsPointerPtr = GetStaticMethodPointer(TEXT("GetTypeIsPointer"));
return CallStaticMethod<bool, void*>(GetTypeIsPointerPtr, type);
}
bool MCore::Type::IsReference(MType* type)
{
MISSING_CODE("TODO: MCore::Type::IsReference"); // TODO: MCore::Type::IsReference
return false;
static void* GetTypeIsReferencePtr = GetStaticMethodPointer(TEXT("GetTypeIsReference"));
return CallStaticMethod<bool, void*>(GetTypeIsReferencePtr, type);
}
const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
@@ -1256,7 +1264,7 @@ void* MMethod::GetThunk()
MMethod* MMethod::InflateGeneric() const
{
// TODO: implement/test this on .NET (eg. C# script that inherits other generic C# script which implements C++ native method)
// This seams to be unused on .NET (Mono required inflating generic class of the script)
return const_cast<MMethod*>(this);
}
@@ -1355,13 +1363,16 @@ MMethod* MProperty::GetSetMethod() const
MObject* MProperty::GetValue(MObject* instance, MObject** exception) const
{
MISSING_CODE("TODO: MProperty::GetValue"); // TODO: MProperty::GetValue
return nullptr;
CHECK_RETURN(_getMethod, nullptr);
return _getMethod->Invoke(instance, nullptr, exception);
}
void MProperty::SetValue(MObject* instance, void* value, MObject** exception) const
{
MISSING_CODE("TODO: MProperty::SetValue"); // TODO: MProperty::SetValue
CHECK(_setMethod);
void* params[1];
params[0] = value;
_setMethod->Invoke(instance, params, exception);
}
bool MProperty::HasAttribute(MClass* monoClass) const

View File

@@ -928,6 +928,12 @@ MClass* MCore::Type::GetClass(MType* type)
return FindClass(mclass);
}
MType* MCore::Type::GetElementType(MType* type)
{
CRASH; // impl this (get type class and call GetElementClass)
return nullptr;
}
int32 MCore::Type::GetSize(MType* type)
{
int32 valueAlignment;