diff --git a/csharp-api/REFrameworkNET/Field.hpp b/csharp-api/REFrameworkNET/Field.hpp index 642a440a2..9265b8910 100644 --- a/csharp-api/REFrameworkNET/Field.hpp +++ b/csharp-api/REFrameworkNET/Field.hpp @@ -2,6 +2,8 @@ #include +#include "TypeDefinition.hpp" + #pragma managed namespace REFrameworkNET { @@ -10,6 +12,7 @@ ref class TypeDefinition; public ref class Field { public: Field(const reframework::API::Field* field) : m_field(field) {} + Field(::REFrameworkFieldHandle handle) : m_field(reinterpret_cast(handle)) {} System::String^ GetName() { return gcnew System::String(m_field->get_name()); diff --git a/csharp-api/REFrameworkNET/ManagedObject.hpp b/csharp-api/REFrameworkNET/ManagedObject.hpp index 32184425b..5b620c682 100644 --- a/csharp-api/REFrameworkNET/ManagedObject.hpp +++ b/csharp-api/REFrameworkNET/ManagedObject.hpp @@ -25,6 +25,15 @@ public ref class ManagedObject : public System::Dynamic::DynamicObject, public S } } + // Double check if we really want to allow this + // We might be better off having a global managed object cache + // instead of AddRef'ing every time we create a new ManagedObject + ManagedObject(ManagedObject^ obj) : m_object(obj->m_object) { + if (m_object != nullptr) { + AddRef(); + } + } + ~ManagedObject() { if (m_object != nullptr) { Release(); diff --git a/csharp-api/REFrameworkNET/Method.cpp b/csharp-api/REFrameworkNET/Method.cpp index f46c309b4..abd12b158 100644 --- a/csharp-api/REFrameworkNET/Method.cpp +++ b/csharp-api/REFrameworkNET/Method.cpp @@ -8,9 +8,13 @@ #include "Field.hpp" #include "API.hpp" +#include "VM.hpp" +#include "SystemString.hpp" #include "Utility.hpp" +using namespace System; + namespace REFrameworkNET { MethodHook^ Method::AddHook(bool ignore_jmp) { return MethodHook::Create(this, ignore_jmp); @@ -38,8 +42,34 @@ REFrameworkNET::InvokeRet^ Method::Invoke(System::Object^ obj, arrayptr(); const auto t = args[i]->GetType(); - if (t == REFrameworkNET::ManagedObject::typeid) { - args2[i] = safe_cast(args[i])->Ptr(); + if (t->IsSubclassOf(REFrameworkNET::IObject::typeid)) { + auto iobj = safe_cast(args[i]); + + if (iobj->IsProperObject()) { + args2[i] = iobj->Ptr(); + } else if (t == REFrameworkNET::TypeDefinition::typeid) { + // TypeDefinitions are wrappers for System.RuntimeTypeHandle + // However there's basically no functions that actually take a System.RuntimeTypeHandle + // so we will just convert it to a System.Type. + if (auto td = iobj->GetTypeDefinition(); td != nullptr) { + if (auto rt = td->GetRuntimeType(); rt != nullptr) { + args2[i] = rt->Ptr(); + } else { + System::Console::WriteLine("TypeDefinition has no runtime type @ arg " + i); + } + } + } else { + args2[i] = nullptr; + System::Console::WriteLine("Unknown IObject type passed to method invocation @ arg " + i); + } + } else if (t == System::String::typeid) { + auto createdStr = VM::CreateString(safe_cast(args[i])); + + if (createdStr != nullptr) { + args2[i] = createdStr->Ptr(); + } else { + System::Console::WriteLine("Error creating string @ arg " + i); + } } else if (t == System::Boolean::typeid) { bool v = System::Convert::ToBoolean(args[i]); args2[i] = (void*)(intptr_t)v; @@ -181,6 +211,14 @@ bool Method::HandleInvokeMember_Internal(System::Object^ obj, System::String^ me result = gcnew REFrameworkNET::TypeDefinition((::REFrameworkTypeDefinitionHandle)tempResult->QWord); break; } + case "System.RuntimeMethodHandle"_fnv: { + result = gcnew REFrameworkNET::Method((::REFrameworkMethodHandle)tempResult->QWord); + break; + } + case "System.RuntimeFieldHandle"_fnv: { + result = gcnew REFrameworkNET::Field((::REFrameworkFieldHandle)tempResult->QWord); + break; + } default: result = tempResult; break; diff --git a/csharp-api/REFrameworkNET/Method.hpp b/csharp-api/REFrameworkNET/Method.hpp index 03d847d89..8dea53be5 100644 --- a/csharp-api/REFrameworkNET/Method.hpp +++ b/csharp-api/REFrameworkNET/Method.hpp @@ -19,6 +19,7 @@ public ref class Method : public System::IEquatable { public: Method(reframework::API::Method* method) : m_method(method) {} + Method(::REFrameworkMethodHandle handle) : m_method(reinterpret_cast(handle)) {} void* GetRaw() { return m_method;