| 1223 | } |
| 1224 | |
| 1225 | bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Span<Variant> paramValues, Variant& result) |
| 1226 | { |
| 1227 | #if USE_CSHARP |
| 1228 | const auto mMethod = (MMethod*)method; |
| 1229 | const int32 parametersCount = mMethod->GetParametersCount();; |
| 1230 | if (paramValues.Length() != parametersCount) |
| 1231 | { |
| 1232 | LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) with invalid parameters amount ({3})", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount, paramValues.Length()); |
| 1233 | return true; |
| 1234 | } |
| 1235 | |
| 1236 | // Get instance object |
| 1237 | void* mInstance = nullptr; |
| 1238 | const bool withInterfaces = !mMethod->IsStatic() && mMethod->GetParentClass()->IsInterface(); |
| 1239 | if (!mMethod->IsStatic()) |
| 1240 | { |
| 1241 | // Box instance into C# object (and validate the type) |
| 1242 | MObject* instanceObject = MUtils::BoxVariant(instance); |
| 1243 | if (!instanceObject) |
| 1244 | { |
| 1245 | LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) without object instance", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount); |
| 1246 | return true; |
| 1247 | } |
| 1248 | const MClass* instanceObjectClass = MCore::Object::GetClass(instanceObject); |
| 1249 | if (!instanceObjectClass->IsSubClassOf(mMethod->GetParentClass(), withInterfaces)) |
| 1250 | { |
| 1251 | LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) with invalid object instance of type '{3}'", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount, String(MUtils::GetClassFullname(instanceObject))); |
| 1252 | return true; |
| 1253 | } |
| 1254 | |
| 1255 | #if USE_NETCORE |
| 1256 | mInstance = instanceObject; |
| 1257 | #else |
| 1258 | // For value-types instance is the actual boxed object data, not te object itself |
| 1259 | mInstance = instanceObjectClass->IsValueType() ? MCore::Object::Unbox(instanceObject) : instanceObject; |
| 1260 | #endif |
| 1261 | } |
| 1262 | |
| 1263 | // Marshal parameters |
| 1264 | void** params = (void**)alloca(parametersCount * sizeof(void*)); |
| 1265 | void** outParams = nullptr; |
| 1266 | bool failed = false; |
| 1267 | bool hasOutParams = false; |
| 1268 | for (int32 paramIdx = 0; paramIdx < parametersCount; paramIdx++) |
| 1269 | { |
| 1270 | Variant& paramValue = paramValues[paramIdx]; |
| 1271 | const bool isOut = mMethod->GetParameterIsOut(paramIdx); |
| 1272 | hasOutParams |= isOut; |
| 1273 | |
| 1274 | // Marshal parameter for managed method |
| 1275 | MType* paramType = mMethod->GetParameterType(paramIdx); |
| 1276 | params[paramIdx] = MUtils::VariantToManagedArgPtr(paramValue, paramType, failed); |
| 1277 | if (failed) |
| 1278 | { |
| 1279 | LOG(Error, "Failed to marshal parameter {5}:{4} of method '{0}.{1}' (args count: {2}), value type: {6}, value: {3}", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount, paramValue, MCore::Type::ToString(paramType), paramIdx, paramValue.Type); |
| 1280 | return true; |
| 1281 | } |
| 1282 | if (isOut && MCore::Type::IsReference(paramType) && MCore::Type::GetType(paramType) == MTypes::Object) |
no test coverage detected