From 130ddf90618d60bc321826061e75945768cea818 Mon Sep 17 00:00:00 2001 From: praydog Date: Sun, 17 Mar 2024 20:49:46 -0700 Subject: [PATCH] .NET: Implement API wrappers on the C++/CLI side --- CMakeLists.txt | 4 + csharp-api/REFrameworkNET/API.cpp | 12 +- csharp-api/REFrameworkNET/API.hpp | 48 ++++- csharp-api/REFrameworkNET/Field.hpp | 75 +++++++ csharp-api/REFrameworkNET/InvokeRet.hpp | 35 ++++ csharp-api/REFrameworkNET/ManagedObject.cpp | 15 ++ csharp-api/REFrameworkNET/ManagedObject.hpp | 46 +++++ .../REFrameworkNET/ManagedSingleton.hpp | 24 +++ csharp-api/REFrameworkNET/Method.cpp | 57 ++++++ csharp-api/REFrameworkNET/Method.hpp | 97 +++++++++ csharp-api/REFrameworkNET/MethodParameter.hpp | 15 ++ csharp-api/REFrameworkNET/Property.hpp | 15 ++ csharp-api/REFrameworkNET/TDB.cpp | 1 + csharp-api/REFrameworkNET/TDB.hpp | 97 +++++++++ csharp-api/REFrameworkNET/TypeDefinition.cpp | 111 +++++++++++ csharp-api/REFrameworkNET/TypeDefinition.hpp | 188 ++++++++++++++++++ csharp-api/REFrameworkNET/TypeInfo.hpp | 16 ++ csharp-api/test/Test/Test.cs | 42 ++-- 18 files changed, 874 insertions(+), 24 deletions(-) create mode 100644 csharp-api/REFrameworkNET/Field.hpp create mode 100644 csharp-api/REFrameworkNET/InvokeRet.hpp create mode 100644 csharp-api/REFrameworkNET/ManagedObject.cpp create mode 100644 csharp-api/REFrameworkNET/ManagedObject.hpp create mode 100644 csharp-api/REFrameworkNET/ManagedSingleton.hpp create mode 100644 csharp-api/REFrameworkNET/Method.cpp create mode 100644 csharp-api/REFrameworkNET/Method.hpp create mode 100644 csharp-api/REFrameworkNET/MethodParameter.hpp create mode 100644 csharp-api/REFrameworkNET/Property.hpp create mode 100644 csharp-api/REFrameworkNET/TDB.cpp create mode 100644 csharp-api/REFrameworkNET/TDB.hpp create mode 100644 csharp-api/REFrameworkNET/TypeDefinition.cpp create mode 100644 csharp-api/REFrameworkNET/TypeDefinition.hpp create mode 100644 csharp-api/REFrameworkNET/TypeInfo.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f8bf7c99c..30bb1c80c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12893,7 +12893,11 @@ if(REF_BUILD_FRAMEWORK AND CMAKE_SIZEOF_VOID_P EQUAL 8) # build-framework list(APPEND csharp-api_SOURCES "csharp-api/Plugin.cpp" "csharp-api/REFrameworkNET/API.cpp" + "csharp-api/REFrameworkNET/ManagedObject.cpp" + "csharp-api/REFrameworkNET/Method.cpp" "csharp-api/REFrameworkNET/PluginManager.cpp" + "csharp-api/REFrameworkNET/TDB.cpp" + "csharp-api/REFrameworkNET/TypeDefinition.cpp" ) list(APPEND csharp-api_SOURCES diff --git a/csharp-api/REFrameworkNET/API.cpp b/csharp-api/REFrameworkNET/API.cpp index 427033be4..505faa58f 100644 --- a/csharp-api/REFrameworkNET/API.cpp +++ b/csharp-api/REFrameworkNET/API.cpp @@ -5,17 +5,19 @@ #include "./API.hpp" +REFrameworkNET::API::API(const REFrameworkPluginInitializeParam* param) +{ + Console::WriteLine("REFrameworkNET.API Constructor called."); + s_api = reframework::API::initialize(param).get(); +} + REFrameworkNET::API::API(uintptr_t param) - : m_api{ reframework::API::initialize(param) } { Console::WriteLine("REFrameworkNET.API Constructor called."); + s_api = reframework::API::initialize((const REFrameworkPluginInitializeParam*)param).get(); } REFrameworkNET::API::~API() { Console::WriteLine("REFrameworkNET.API Destructor called."); -} - -reframework::API^ REFrameworkNET::API::Get() { - return m_api; } \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/API.hpp b/csharp-api/REFrameworkNET/API.hpp index 0a5c6283c..39e362675 100644 --- a/csharp-api/REFrameworkNET/API.hpp +++ b/csharp-api/REFrameworkNET/API.hpp @@ -1,8 +1,18 @@ #pragma once + +#include + #pragma managed +#include + +#include "TypeInfo.hpp" +#include "ManagedObject.hpp" +#include "TDB.hpp" +#include "ManagedSingleton.hpp" + namespace reframework { -ref class API; +class API; } using namespace System; @@ -11,12 +21,44 @@ namespace REFrameworkNET { public ref class API { public: + API(const REFrameworkPluginInitializeParam* param); API(uintptr_t param); ~API(); - reframework::API^ Get(); + inline REFrameworkNET::TDB^ GetTDB() { + return gcnew REFrameworkNET::TDB(s_api->tdb()); + } + + inline REFrameworkNET::ManagedObject^ GetManagedSingleton(System::String^ name) { + auto result = s_api->get_managed_singleton(msclr::interop::marshal_as(name)); + + if (result == nullptr) { + return nullptr; + } + + return gcnew REFrameworkNET::ManagedObject(result); + } + + inline System::Collections::Generic::List^ GetManagedSingletons() { + auto singletons = s_api->get_managed_singletons(); + auto result = gcnew System::Collections::Generic::List(); + + for (auto& singleton : singletons) { + if (singleton.instance == nullptr) { + continue; + } + + result->Add(gcnew REFrameworkNET::ManagedSingleton( + gcnew REFrameworkNET::ManagedObject(singleton.instance), + gcnew REFrameworkNET::TypeDefinition(singleton.t), + gcnew REFrameworkNET::TypeInfo(singleton.type_info) + )); + } + + return result; + } protected: - reframework::API^ m_api; + static reframework::API* s_api; }; } \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/Field.hpp b/csharp-api/REFrameworkNET/Field.hpp new file mode 100644 index 000000000..57e5a22de --- /dev/null +++ b/csharp-api/REFrameworkNET/Field.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include + +#pragma managed + +namespace REFrameworkNET { +ref class TypeDefinition; + +public ref class Field { +public: + Field(const reframework::API::Field* field) : m_field(field) {} + + System::String^ GetName() { + return gcnew System::String(m_field->get_name()); + } + + TypeDefinition^ GetDeclaringType() { + auto t = m_field->get_declaring_type(); + + if (t == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(t); + } + + TypeDefinition^ GetType() { + auto t = m_field->get_type(); + + if (t == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(t); + } + + uint32_t GetOffsetFromBase() { + return m_field->get_offset_from_base(); + } + + uint32_t GetOffsetFromFieldPtr() { + return m_field->get_offset_from_fieldptr(); + } + + uint32_t GetFlags() { + return m_field->get_flags(); + } + + bool IsStatic() { + return m_field->is_static(); + } + + bool IsLiteral() { + return m_field->is_literal(); + } + + uintptr_t GetInitDataPtr() { + return (uintptr_t)m_field->get_init_data(); + } + + uintptr_t GetDataRaw(uintptr_t obj, bool isValueType) { + return (uintptr_t)m_field->get_data_raw((void*)obj, isValueType); + } + + // I have no idea if this will work correctly + template + T GetData(uintptr_t obj, bool isValueType) { + return m_field->get_data((void*)obj, isValueType); + } + +private: + const reframework::API::Field* m_field; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/InvokeRet.hpp b/csharp-api/REFrameworkNET/InvokeRet.hpp new file mode 100644 index 000000000..8bb83b6e5 --- /dev/null +++ b/csharp-api/REFrameworkNET/InvokeRet.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include + +#pragma managed + +namespace REFrameworkNET { +public ref struct InvokeRet { + InvokeRet(const reframework::InvokeRet& ret) { + Bytes = gcnew array(ret.bytes.size()); + for (size_t i = 0; i < ret.bytes.size(); i++) { + Bytes[i] = ret.bytes[i]; + } + Byte = ret.byte; + Word = ret.word; + DWord = ret.dword; + F = ret.f; + QWord = ret.qword; + D = ret.d; + Ptr = gcnew System::UIntPtr(ret.ptr); + ExceptionThrown = ret.exception_thrown; + } + + // TODO: improve this? Does .NET have unions? + property array^ Bytes; + property uint8_t Byte; + property uint16_t Word; + property uint32_t DWord; + property float F; + property uint64_t QWord; + property double D; + property System::Object^ Ptr; + property bool ExceptionThrown; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/ManagedObject.cpp b/csharp-api/REFrameworkNET/ManagedObject.cpp new file mode 100644 index 000000000..0905dcb5c --- /dev/null +++ b/csharp-api/REFrameworkNET/ManagedObject.cpp @@ -0,0 +1,15 @@ +#include "TypeDefinition.hpp" + +#include "ManagedObject.hpp" + +namespace REFrameworkNET { + TypeDefinition^ ManagedObject::GetTypeDefinition() { + auto result = m_object->get_type_definition(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(result); + } +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/ManagedObject.hpp b/csharp-api/REFrameworkNET/ManagedObject.hpp new file mode 100644 index 000000000..d4745d808 --- /dev/null +++ b/csharp-api/REFrameworkNET/ManagedObject.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#pragma managed + +namespace REFrameworkNET { +ref class TypeDefinition; + +public ref class ManagedObject { +public: + ManagedObject(reframework::API::ManagedObject* obj) : m_object(obj) { + AddRef(); + } + ManagedObject(::REFrameworkManagedObjectHandle handle) : m_object(reinterpret_cast(handle)) { + AddRef(); + } + + ~ManagedObject() { + if (m_object != nullptr) { + Release(); + } + } + + void AddRef() { + m_object->add_ref(); + } + + void Release() { + m_object->release(); + } + + void* Ptr() { + return (void*)m_object; + } + + uintptr_t GetAddress() { + return (uintptr_t)m_object; + } + + TypeDefinition^ GetTypeDefinition(); + +private: + reframework::API::ManagedObject* m_object; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/ManagedSingleton.hpp b/csharp-api/REFrameworkNET/ManagedSingleton.hpp new file mode 100644 index 000000000..d218fb93f --- /dev/null +++ b/csharp-api/REFrameworkNET/ManagedSingleton.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#pragma managed + +namespace REFrameworkNET { +ref class ManagedObject; +ref class TypeDefinition; +ref class TypeInfo; + +public ref struct ManagedSingleton { + ManagedSingleton(ManagedObject^ instance, TypeDefinition^ type, TypeInfo^ typeInfo) + { + Instance = instance; + Type = type; + TypeInfo = typeInfo; + } + + property ManagedObject^ Instance; + property TypeDefinition^ Type; + property TypeInfo^ TypeInfo; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/Method.cpp b/csharp-api/REFrameworkNET/Method.cpp new file mode 100644 index 000000000..b7a56a612 --- /dev/null +++ b/csharp-api/REFrameworkNET/Method.cpp @@ -0,0 +1,57 @@ +#include "ManagedObject.hpp" + +#include "Method.hpp" + +namespace REFrameworkNET { +REFrameworkNET::InvokeRet^ Method::Invoke(System::Object^ obj, array^ args) { + // We need to convert the managed objects to 8 byte representations + std::vector args2{}; + args2.resize(args->Length); + + for (int i = 0; i < args->Length; ++i) { + //args2[i] = args[i]->ptr(); + const auto t = args[i]->GetType(); + + if (t == System::Byte::typeid) { + uint8_t v = System::Convert::ToByte(args[i]); + args2[i] = (void*)(uint64_t)v; + } else if (t == System::UInt16::typeid) { + uint16_t v = System::Convert::ToUInt16(args[i]); + args2[i] = (void*)(uint64_t)v; + } else if (t == System::UInt32::typeid) { + uint32_t v = System::Convert::ToUInt32(args[i]); + args2[i] = (void*)(uint64_t)v; + } else if (t == System::Single::typeid) { + float v = System::Convert::ToSingle(args[i]); + args2[i] = (void*)(uint64_t)v; + } else if (t == System::UInt64::typeid) { + uint64_t v = System::Convert::ToUInt64(args[i]); + args2[i] = (void*)(uint64_t)v; + } else if (t == System::Double::typeid) { + double v = System::Convert::ToDouble(args[i]); + args2[i] = (void*)(uint64_t)v; + } else if (t == System::IntPtr::typeid) { + args2[i] = (void*)(uint64_t)System::Convert::ToInt64(args[i]); + } else { + //args2[i] = args[i]->ptr(); + } + } + + void* obj_ptr = nullptr; + + if (obj != nullptr) { + const auto obj_t = obj->GetType(); + if (obj_t == System::IntPtr::typeid || obj_t == System::UIntPtr::typeid) { + obj_ptr = (void*)(uint64_t)System::Convert::ToInt64(obj); + } else if (obj_t == REFrameworkNET::ManagedObject::typeid) { + obj_ptr = safe_cast(obj)->Ptr(); + } else { + //obj_ptr = obj->ptr(); + } + } + + const auto native_result = m_method->invoke((reframework::API::ManagedObject*)obj_ptr, args2); + + return gcnew REFrameworkNET::InvokeRet(native_result); +} +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/Method.hpp b/csharp-api/REFrameworkNET/Method.hpp new file mode 100644 index 000000000..5749eef36 --- /dev/null +++ b/csharp-api/REFrameworkNET/Method.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include + +#pragma managed + +#include "InvokeRet.hpp" +#include "MethodParameter.hpp" + +namespace REFrameworkNET { +public ref class Method { +public: + Method(reframework::API::Method* method) : m_method(method) {} + + REFrameworkNET::InvokeRet^ Invoke(System::Object^ obj, array^ args); + + /*Void* GetFunctionRaw() { + return m_method->get_function_raw(); + }*/ + + System::String^ GetName() { + return gcnew System::String(m_method->get_name()); + } + + TypeDefinition^ GetDeclaringType() { + auto result = m_method->get_declaring_type(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(result); + } + + TypeDefinition^ GetReturnType() { + auto result = m_method->get_return_type(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(result); + } + + uint32_t GetNumParams() { + return m_method->get_num_params(); + } + + System::Collections::Generic::List^ GetParameters() { + const auto params = m_method->get_params(); + + auto ret = gcnew System::Collections::Generic::List(); + + for (auto& p : params) { + ret->Add(gcnew REFrameworkNET::MethodParameter(p)); + } + + return ret; + } + + uint32_t GetIndex() { + return m_method->get_index(); + } + + int32_t GetVirtualIndex() { + return m_method->get_virtual_index(); + } + + bool IsStatic() { + return m_method->is_static(); + } + + uint16_t GetFlags() { + return m_method->get_flags(); + } + + uint16_t GetImplFlags() { + return m_method->get_impl_flags(); + } + + uint32_t GetInvokeID() { + return m_method->get_invoke_id(); + } + + // hmm... + /*UInt32 AddHook(pre_fn, post_fn, Boolean ignore_jmp) { + return m_method->add_hook(pre_fn, post_fn, ignore_jmp); + }*/ + + void RemoveHook(uint32_t hook_id) { + m_method->remove_hook(hook_id); + } + +private: + reframework::API::Method* m_method; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/MethodParameter.hpp b/csharp-api/REFrameworkNET/MethodParameter.hpp new file mode 100644 index 000000000..7b39ae5d8 --- /dev/null +++ b/csharp-api/REFrameworkNET/MethodParameter.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "TypeDefinition.hpp" + +namespace REFrameworkNET { +public ref struct MethodParameter { + MethodParameter(const REFrameworkMethodParameter& p) { + Name = gcnew System::String(p.name); + Type = gcnew REFrameworkNET::TypeDefinition(p.t); + } + + property System::String^ Name; + property REFrameworkNET::TypeDefinition^ Type; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/Property.hpp b/csharp-api/REFrameworkNET/Property.hpp new file mode 100644 index 000000000..89a400d28 --- /dev/null +++ b/csharp-api/REFrameworkNET/Property.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#pragma managed + +namespace REFrameworkNET { +public ref class Property { +public: + Property(const reframework::API::Property* prop) : m_prop(prop) {} + +private: + const reframework::API::Property* m_prop; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/TDB.cpp b/csharp-api/REFrameworkNET/TDB.cpp new file mode 100644 index 000000000..42f30d771 --- /dev/null +++ b/csharp-api/REFrameworkNET/TDB.cpp @@ -0,0 +1 @@ +#include "TDB.hpp" \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/TDB.hpp b/csharp-api/REFrameworkNET/TDB.hpp new file mode 100644 index 000000000..dbbec6127 --- /dev/null +++ b/csharp-api/REFrameworkNET/TDB.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include + +#pragma managed + +#include +#include "TypeDefinition.hpp" +#include "Method.hpp" +#include "Field.hpp" +#include "Property.hpp" + +namespace REFrameworkNET { +public ref class TDB { +public: + TDB(reframework::API::TDB* tdb) : m_tdb(tdb) {} + + uintptr_t GetAddress() { + return (uintptr_t)m_tdb; + } + + uint32_t GetNumTypes() { + return m_tdb->get_num_types(); + } + + uint32_t GetNumMethods() { + return m_tdb->get_num_methods(); + } + + uint32_t GetNumFields() { + return m_tdb->get_num_fields(); + } + + uint32_t GetNumProperties() { + return m_tdb->get_num_properties(); + } + + uint32_t GetStringsSize() { + return m_tdb->get_strings_size(); + } + + uint32_t GetRawDataSize() { + return m_tdb->get_raw_data_size(); + } + + /*public SByte* GetStringDatabase() { + return m_tdb->get_string_database(); + } + + public Byte* GetRawDatabase() { + return m_tdb->get_raw_database(); + }*/ + + System::Span^ GetRawData() { + return gcnew System::Span(m_tdb->get_raw_database(), m_tdb->get_raw_data_size()); + } + + System::String^ GetString(uint32_t index) { + return gcnew System::String(m_tdb->get_string_database() + index); + } + + TypeDefinition^ GetType(uint32_t index) { + return gcnew TypeDefinition(m_tdb->get_type(index)); + } + + TypeDefinition^ FindType(System::String^ name) { + return gcnew TypeDefinition(m_tdb->find_type(msclr::interop::marshal_as(name))); + } + + TypeDefinition^ FindTypeByFqn(uint32_t fqn) { + return gcnew TypeDefinition(m_tdb->find_type_by_fqn(fqn)); + } + + Method^ GetMethod(uint32_t index) { + return gcnew Method(m_tdb->get_method(index)); + } + + Method^ FindMethod(System::String^ type_name, System::String^ name) { + return gcnew Method(m_tdb->find_method(msclr::interop::marshal_as(type_name), msclr::interop::marshal_as(name))); + } + + Field^ GetField(uint32_t index) { + return gcnew Field(m_tdb->get_field(index)); + } + + Field^ FindField(System::String^ type_name, System::String^ name) { + return gcnew Field(m_tdb->find_field(msclr::interop::marshal_as(type_name), msclr::interop::marshal_as(name))); + } + + Property^ GetProperty(uint32_t index) { + return gcnew Property(m_tdb->get_property(index)); + } + +private: + reframework::API::TDB* m_tdb; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/TypeDefinition.cpp b/csharp-api/REFrameworkNET/TypeDefinition.cpp new file mode 100644 index 000000000..ffadb165a --- /dev/null +++ b/csharp-api/REFrameworkNET/TypeDefinition.cpp @@ -0,0 +1,111 @@ +#include "Method.hpp" +#include "Field.hpp" +#include "Property.hpp" +#include "ManagedObject.hpp" + +#include "TypeDefinition.hpp" + +namespace REFrameworkNET { + REFrameworkNET::Method^ TypeDefinition::FindMethod(System::String^ name) + { + auto result = m_type->find_method(msclr::interop::marshal_as(name)); + + if (result == nullptr) { + return nullptr; + } + + return gcnew REFrameworkNET::Method(result); + } + + REFrameworkNET::Field^ TypeDefinition::FindField(System::String^ name) + { + auto result = m_type->find_field(msclr::interop::marshal_as(name)); + + if (result == nullptr) { + return nullptr; + } + + return gcnew Field(result); + } + + REFrameworkNET::Property^ TypeDefinition::FindProperty(System::String^ name) + { + auto result = m_type->find_property(msclr::interop::marshal_as(name)); + + if (result == nullptr) { + return nullptr; + } + + return gcnew Property(result); + } + + System::Collections::Generic::List^ TypeDefinition::GetMethods() + { + auto methods = m_type->get_methods(); + auto result = gcnew System::Collections::Generic::List(); + + for (auto& method : methods) { + if (method == nullptr) { + continue; + } + + result->Add(gcnew Method(method)); + } + + return result; + } + + System::Collections::Generic::List^ TypeDefinition::GetFields() + { + auto fields = m_type->get_fields(); + auto result = gcnew System::Collections::Generic::List(); + + for (auto& field : fields) { + if (field == nullptr) { + continue; + } + + result->Add(gcnew Field(field)); + } + + return result; + } + + System::Collections::Generic::List^ TypeDefinition::GetProperties() + { + auto properties = m_type->get_properties(); + auto result = gcnew System::Collections::Generic::List(); + + for (auto& property : properties) { + if (property == nullptr) { + continue; + } + + result->Add(gcnew Property(property)); + } + + return result; + } + + ManagedObject^ TypeDefinition::CreateInstance(int32_t flags) + { + auto result = m_type->create_instance(flags); + + if (result == nullptr) { + return nullptr; + } + + return gcnew ManagedObject(result); + } + + ManagedObject^ TypeDefinition::GetRuntimeType() + { + auto result = m_type->get_runtime_type(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew ManagedObject(result); + } +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/TypeDefinition.hpp b/csharp-api/REFrameworkNET/TypeDefinition.hpp new file mode 100644 index 000000000..93207ffdb --- /dev/null +++ b/csharp-api/REFrameworkNET/TypeDefinition.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include + +#pragma managed + +#include + +namespace REFrameworkNET { +ref class ManagedObject; +ref class Method; +ref class Field; +ref class Property; + +public ref class TypeDefinition +{ +public: + TypeDefinition(reframework::API::TypeDefinition* td) : m_type(td) {} + TypeDefinition(::REFrameworkTypeDefinitionHandle handle) : m_type(reinterpret_cast(handle)) {} + + operator reframework::API::TypeDefinition*() { + return (reframework::API::TypeDefinition*)m_type; + } + + uint32_t GetIndex() + { + return m_type->get_index(); + } + + uint32_t GetSize() + { + return m_type->get_size(); + } + + uint32_t GetValuetypeSize() + { + return m_type->get_valuetype_size(); + } + + uint32_t GetFqn() + { + return m_type->get_fqn(); + } + + System::String^ GetName() + { + return gcnew System::String(m_type->get_name()); + } + + System::String^ GetNamespace() + { + return gcnew System::String(m_type->get_namespace()); + } + + System::String^ GetFullName() + { + return gcnew System::String(m_type->get_full_name().c_str()); + } + + bool HasFieldPtrOffset() + { + return m_type->has_fieldptr_offset(); + } + + int32_t GetFieldPtrOffset() + { + return m_type->get_fieldptr_offset(); + } + + uint32_t GetNumMethods() + { + return m_type->get_num_methods(); + } + + uint32_t GetNumFields() + { + return m_type->get_num_fields(); + } + + uint32_t GetNumProperties() + { + return m_type->get_num_properties(); + } + + bool IsDerivedFrom(System::String^ other) + { + return m_type->is_derived_from(msclr::interop::marshal_as(other).c_str()); + } + + bool IsDerivedFrom(TypeDefinition^ other) + { + return m_type->is_derived_from(other); + } + + bool IsValueType() + { + return m_type->is_valuetype(); + } + + bool IsEnum() + { + return m_type->is_enum(); + } + + bool IsByRef() + { + return m_type->is_by_ref(); + } + + bool IsPointer() + { + return m_type->is_pointer(); + } + + bool IsPrimitive() + { + return m_type->is_primitive(); + } + + uint32_t GetVmObjType() + { + return m_type->get_vm_obj_type(); + } + + REFrameworkNET::Method^ FindMethod(System::String^ name); + Field^ FindField(System::String^ name); + Property^ FindProperty(System::String^ name); + + System::Collections::Generic::List^ GetMethods(); + System::Collections::Generic::List^ GetFields(); + System::Collections::Generic::List^ GetProperties(); + + ManagedObject^ CreateInstance(int32_t flags); + + TypeDefinition^ GetParentType() + { + auto result = m_type->get_parent_type(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(result); + } + + TypeDefinition^ GetDeclaringType() + { + auto result = m_type->get_declaring_type(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(result); + } + + TypeDefinition^ GetUnderlyingType() + { + auto result = m_type->get_underlying_type(); + + if (result == nullptr) { + return nullptr; + } + + return gcnew TypeDefinition(result); + } + + /*API.TypeInfo GetTypeInfo() + { + return m_type->get_type_info(); + }*/ + + ManagedObject^ GetRuntimeType(); + + /*Void* GetInstance() + { + return m_type->get_instance(); + } + + Void* CreateInstanceDeprecated() + { + return m_type->create_instance_deprecated(); + }*/ + +private: + reframework::API::TypeDefinition* m_type; +}; +} \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/TypeInfo.hpp b/csharp-api/REFrameworkNET/TypeInfo.hpp new file mode 100644 index 000000000..165418661 --- /dev/null +++ b/csharp-api/REFrameworkNET/TypeInfo.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#pragma managed + +namespace REFrameworkNET { +public ref class TypeInfo { +public: + TypeInfo(reframework::API::TypeInfo* typeInfo) : m_typeInfo(typeInfo) {} + TypeInfo(::REFrameworkTypeInfoHandle handle) : m_typeInfo(reinterpret_cast(handle)) {} + +private: + reframework::API::TypeInfo* m_typeInfo; +}; +}; \ No newline at end of file diff --git a/csharp-api/test/Test/Test.cs b/csharp-api/test/Test/Test.cs index 5caf1f06a..e92665083 100644 --- a/csharp-api/test/Test/Test.cs +++ b/csharp-api/test/Test/Test.cs @@ -90,41 +90,51 @@ private static string GetParameterInvocation(ParameterInfo[] parameters) } class REFrameworkPlugin { - public static void Main(REFrameworkNET.API api_) { + public static void Main(REFrameworkNET.API api) { Console.WriteLine("Testing REFrameworkAPI..."); // Convert api.Get() type to pass to GenerateWrapper - var currentDir = Directory.GetCurrentDirectory(); + /*var currentDir = Directory.GetCurrentDirectory(); var targetType = typeof(reframework.API.Method); var outputPath = Path.Combine(currentDir, "MethodWrapper.cs"); ApiWrapperGenerator.GenerateWrapper(targetType, outputPath); // Open in explorer - System.Diagnostics.Process.Start("explorer.exe", currentDir); + System.Diagnostics.Process.Start("explorer.exe", currentDir);*/ - var api = new APIWrapper(api_.Get()); var tdb = api.GetTDB(); Console.WriteLine(tdb.GetNumTypes().ToString() + " types"); - /*var typesSorted = new System.Collections.Generic.List(); + for (uint i = 0; i < 50; i++) { + var type = tdb.GetType(i); + Console.WriteLine(type.GetFullName()); - for (uint i = 0; i < tdb.GetNumTypes(); i++) { - var t = tdb.GetType(i); - if (t == null) { - continue; + var methods = type.GetMethods(); + + foreach (var method in methods) { + var returnT = method.GetReturnType(); + var returnTName = returnT != null ? returnT.GetFullName() : "null"; + + Console.WriteLine(" " + returnTName + " " + method.GetName()); } - typesSorted.Add(t.GetFullName()); + var fields = type.GetFields(); + + foreach (var field in fields) { + var t = field.GetType(); + string tName = t != null ? t.GetFullName() : "null"; + Console.WriteLine(" " + tName + " " + field.GetName() + " @ " + "0x" + field.GetOffsetFromBase().ToString("X")); + } } - typesSorted.Sort();*/ + Console.WriteLine("Done with types"); var singletons = api.GetManagedSingletons(); foreach (var singletonDesc in singletons) { - var singleton = new ManagedObjectWrapper(singletonDesc.Instance); + var singleton = singletonDesc.Instance; Console.WriteLine(singleton.GetTypeDefinition().GetFullName()); @@ -135,7 +145,7 @@ public static void Main(REFrameworkNET.API api_) { foreach (var method in methods) { string postfix = ""; foreach (var param in method.GetParameters()) { - postfix += new TypeDefinitionWrapper(param.Type).GetFullName() + " " + param.Name + ", "; + postfix += param.Type.GetFullName() + " " + param.Name + ", "; } Console.WriteLine(" " + method.GetName() + " " + postfix); @@ -144,11 +154,11 @@ public static void Main(REFrameworkNET.API api_) { var fields = td.GetFields(); foreach (var field in fields) { - Console.WriteLine(" " + field.get_name()); + Console.WriteLine(" " + field.GetName()); } } - var sceneManager = api.GetNativeSingleton("via.SceneManager"); + /*var sceneManager = api.GetNativeSingleton("via.SceneManager"); Console.WriteLine("sceneManager: " + sceneManager); var sceneManager_t = tdb.FindType("via.SceneManager"); Console.WriteLine("sceneManager_t: " + sceneManager_t); @@ -165,6 +175,6 @@ public static void Main(REFrameworkNET.API api_) { Console.WriteLine("set_TimeScale: " + set_TimeScale); set_TimeScale.Invoke(scene, new object[]{ 0.1f }); - } + }*/ } }; \ No newline at end of file