Add support for accessing scripting properties via ManagedBinaryModule fields API

This commit is contained in:
Wojtek Figat
2023-08-19 17:45:42 +02:00
parent de6254b5a5
commit 3498806588

View File

@@ -9,6 +9,7 @@
#include "ManagedCLR/MClass.h"
#include "ManagedCLR/MMethod.h"
#include "ManagedCLR/MField.h"
#include "ManagedCLR/MProperty.h"
#include "ManagedCLR/MUtils.h"
#include "ManagedCLR/MException.h"
#include "FlaxEngine.Gen.h"
@@ -1324,47 +1325,97 @@ void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSi
#endif
}
// Pointers with the highest bit turned on are properties
#if PLATFORM_64BITS
#define ManagedBinaryModuleFieldIsPropertyBit (uintptr)(1ull << 63)
#else
#define ManagedBinaryModuleFieldIsPropertyBit (uintptr)(1ul << 31)
#endif
void* ManagedBinaryModule::FindField(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name)
{
const ScriptingType& type = typeHandle.GetType();
return type.ManagedClass ? type.ManagedClass->GetField(name.Get()) : nullptr;
void* result = type.ManagedClass ? type.ManagedClass->GetField(name.Get()) : nullptr;
if (!result && type.ManagedClass)
{
result = type.ManagedClass->GetProperty(name.Get());
if (result)
result = (void*)((uintptr)result | ManagedBinaryModuleFieldIsPropertyBit);
}
return result;
}
void ManagedBinaryModule::GetFieldSignature(void* field, ScriptingTypeFieldSignature& fieldSignature)
{
#if USE_CSHARP
const auto mField = (MField*)field;
fieldSignature.Name = mField->GetName();
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType()));
fieldSignature.IsStatic = mField->IsStatic();
if ((uintptr)field & ManagedBinaryModuleFieldIsPropertyBit)
{
const auto mProperty = (MProperty*)((uintptr)field & ~ManagedBinaryModuleFieldIsPropertyBit);
fieldSignature.Name = mProperty->GetName();
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mProperty->GetType()));
fieldSignature.IsStatic = mProperty->IsStatic();
}
else
{
const auto mField = (MField*)field;
fieldSignature.Name = mField->GetName();
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType()));
fieldSignature.IsStatic = mField->IsStatic();
}
#endif
}
bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Variant& result)
{
#if USE_CSHARP
const auto mField = (MField*)field;
bool isStatic;
MClass* parentClass;
StringAnsiView name;
if ((uintptr)field & ManagedBinaryModuleFieldIsPropertyBit)
{
const auto mProperty = (MProperty*)((uintptr)field & ~ManagedBinaryModuleFieldIsPropertyBit);
isStatic = mProperty->IsStatic();
parentClass = mProperty->GetParentClass();
name = mProperty->GetName();
}
else
{
const auto mField = (MField*)field;
isStatic = mField->IsStatic();
parentClass = mField->GetParentClass();
name = mField->GetName();
}
// Get instance object
MObject* instanceObject = nullptr;
if (!mField->IsStatic())
if (!isStatic)
{
// Box instance into C# object
instanceObject = MUtils::BoxVariant(instance);
// Validate instance
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(mField->GetParentClass()))
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(parentClass))
{
if (!instanceObject)
LOG(Error, "Failed to get field '{0}.{1}' without object instance", String(mField->GetParentClass()->GetFullName()), String(mField->GetName()));
LOG(Error, "Failed to get '{0}.{1}' without object instance", String(parentClass->GetFullName()), String(name));
else
LOG(Error, "Failed to get field '{0}.{1}' with invalid object instance of type '{2}'", String(mField->GetParentClass()->GetFullName()), String(mField->GetName()), String(MUtils::GetClassFullname(instanceObject)));
LOG(Error, "Failed to get '{0}.{1}' with invalid object instance of type '{2}'", String(parentClass->GetFullName()), String(name), String(MUtils::GetClassFullname(instanceObject)));
return true;
}
}
// Get the value
MObject* resultObject = mField->GetValueBoxed(instanceObject);
MObject* resultObject;
if ((uintptr)field & ManagedBinaryModuleFieldIsPropertyBit)
{
const auto mProperty = (MProperty*)((uintptr)field & ~ManagedBinaryModuleFieldIsPropertyBit);
resultObject = mProperty->GetValue(instanceObject, nullptr);
}
else
{
const auto mField = (MField*)field;
resultObject = mField->GetValueBoxed(instanceObject);
}
result = MUtils::UnboxVariant(resultObject);
return false;
#else
@@ -1375,29 +1426,54 @@ bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Va
bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value)
{
#if USE_CSHARP
const auto mField = (MField*)field;
bool isStatic;
MClass* parentClass;
StringAnsiView name;
if ((uintptr)field & ManagedBinaryModuleFieldIsPropertyBit)
{
const auto mProperty = (MProperty*)((uintptr)field & ~ManagedBinaryModuleFieldIsPropertyBit);
isStatic = mProperty->IsStatic();
parentClass = mProperty->GetParentClass();
name = mProperty->GetName();
}
else
{
const auto mField = (MField*)field;
isStatic = mField->IsStatic();
parentClass = mField->GetParentClass();
name = mField->GetName();
}
// Get instance object
MObject* instanceObject = nullptr;
if (!mField->IsStatic())
if (!isStatic)
{
// Box instance into C# object
instanceObject = MUtils::BoxVariant(instance);
// Validate instance
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(mField->GetParentClass()))
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(parentClass))
{
if (!instanceObject)
LOG(Error, "Failed to set field '{0}.{1}' without object instance", String(mField->GetParentClass()->GetFullName()), String(mField->GetName()));
LOG(Error, "Failed to set '{0}.{1}' without object instance", String(parentClass->GetFullName()), String(name));
else
LOG(Error, "Failed to set field '{0}.{1}' with invalid object instance of type '{2}'", String(mField->GetParentClass()->GetFullName()), String(mField->GetName()), String(MUtils::GetClassFullname(instanceObject)));
LOG(Error, "Failed to set '{0}.{1}' with invalid object instance of type '{2}'", String(parentClass->GetFullName()), String(name), String(MUtils::GetClassFullname(instanceObject)));
return true;
}
}
// Set the value
bool failed = false;
mField->SetValue(instanceObject, MUtils::VariantToManagedArgPtr(value, mField->GetType(), failed));
if ((uintptr)field & ManagedBinaryModuleFieldIsPropertyBit)
{
const auto mProperty = (MProperty*)((uintptr)field & ~ManagedBinaryModuleFieldIsPropertyBit);
mProperty->SetValue(instanceObject, MUtils::BoxVariant(value), nullptr);
}
else
{
const auto mField = (MField*)field;
mField->SetValue(instanceObject, MUtils::VariantToManagedArgPtr(value, mField->GetType(), failed));
}
return failed;
#else
return true;