diff --git a/csharp-api/REFrameworkNET/Method.cpp b/csharp-api/REFrameworkNET/Method.cpp index 5f9a8c2ae..88c162892 100644 --- a/csharp-api/REFrameworkNET/Method.cpp +++ b/csharp-api/REFrameworkNET/Method.cpp @@ -6,11 +6,18 @@ #include "Method.hpp" #include "Field.hpp" +#include "API.hpp" + #include "Utility.hpp" namespace REFrameworkNET { REFrameworkNET::InvokeRet^ Method::Invoke(System::Object^ obj, array^ args) { - // We need to convert the managed objects to 8 byte representations + if (obj == nullptr && !this->IsStatic()) { + System::String^ declaringName = this->GetDeclaringType() != nullptr ? this->GetDeclaringType()->GetFullName() : "Unknown"; + System::String^ errorStr = "Cannot invoke a non-static method without an object (" + declaringName + "." + this->GetName() + ")"; + REFrameworkNET::API::LogError(errorStr); + throw gcnew System::InvalidOperationException(errorStr); + } std::vector args2{}; diff --git a/csharp-api/REFrameworkNET/NativeObject.hpp b/csharp-api/REFrameworkNET/NativeObject.hpp index 33fbb46bf..156a4f610 100644 --- a/csharp-api/REFrameworkNET/NativeObject.hpp +++ b/csharp-api/REFrameworkNET/NativeObject.hpp @@ -3,6 +3,7 @@ #include #include "TypeDefinition.hpp" +#include "InvokeRet.hpp" namespace REFrameworkNET { ref class InvokeRet; @@ -11,19 +12,39 @@ ref class InvokeRet; // However, they still have reflection information associated with them // So this intends to be the "ManagedObject" class for native objects // So we can easily interact with them in C# -public ref class NativeObject : public System::Dynamic::DynamicObject +public ref class NativeObject : public System::Dynamic::DynamicObject, public System::Collections::IEnumerable { public: NativeObject(uintptr_t obj, TypeDefinition^ t){ + if (t == nullptr) { + throw gcnew System::ArgumentNullException("t"); + } + m_object = (void*)obj; m_type = t; } - NativeObject(void* obj, TypeDefinition^ t){ + NativeObject(void* obj, TypeDefinition^ t) { + if (t == nullptr) { + throw gcnew System::ArgumentNullException("t"); + } + m_object = obj; m_type = t; } + // For invoking static methods + // e.g. NativeObject^ obj = new NativeObject(TypeDefinition::GetType("System.AppDomain")); + // obj.get_CurrentDomain().GetAssemblies(); + NativeObject(TypeDefinition^ t) { + if (t == nullptr) { + throw gcnew System::ArgumentNullException("t"); + } + + m_type = t; + m_object = nullptr; + } + TypeDefinition^ GetTypeDefinition() { return m_type; } @@ -41,6 +62,69 @@ public ref class NativeObject : public System::Dynamic::DynamicObject bool HandleInvokeMember_Internal(System::String^ methodName, array^ args, System::Object^% result); virtual bool TryInvokeMember(System::Dynamic::InvokeMemberBinder^ binder, array^ args, System::Object^% result) override; +public: + // IEnumerable implementation + virtual System::Collections::IEnumerator^ GetEnumerator() { + return gcnew NativeObjectEnumerator(this); + } + +private: + ref class NativeObjectEnumerator : public System::Collections::IEnumerator + { + int position = -1; + NativeObject^ nativeObject; + + public: + NativeObjectEnumerator(NativeObject^ nativeObject) { + this->nativeObject = nativeObject; + } + + // IEnumerator implementation + virtual bool MoveNext() { + int itemCount = GetItemCount(); + if (position < itemCount - 1) { + position++; + return true; + } + return false; + } + + virtual void Reset() { + position = -1; + } + + virtual property System::Object^ Current { + System::Object^ get() { + if (position == -1 || position >= GetItemCount()) { + throw gcnew System::InvalidOperationException(); + } + + System::Object^ result = nullptr; + if (nativeObject->HandleInvokeMember_Internal("get_Item", gcnew array{ position }, result)) { + return result; + } + + return nullptr; + } + } + + private: + int GetItemCount() { + //return nativeObject->Invoke("get_Count", gcnew array{})->DWord; + System::Object^ result = nullptr; + + if (nativeObject->HandleInvokeMember_Internal("get_Count", gcnew array{}, result)) { + return (int)result; + } + + if (nativeObject->HandleInvokeMember_Internal("get_Length", gcnew array{}, result)) { + return (int)result; + } + + return 0; + } + }; + private: void* m_object{}; TypeDefinition^ m_type{}; diff --git a/csharp-api/REFrameworkNET/TypeDefinition.cpp b/csharp-api/REFrameworkNET/TypeDefinition.cpp index b3630ce5a..86df9ee28 100644 --- a/csharp-api/REFrameworkNET/TypeDefinition.cpp +++ b/csharp-api/REFrameworkNET/TypeDefinition.cpp @@ -3,10 +3,15 @@ #include "Field.hpp" #include "Property.hpp" #include "ManagedObject.hpp" +#include "NativeObject.hpp" #include "TypeDefinition.hpp" namespace REFrameworkNET { + NativeObject^ TypeDefinition::Statics::get() { + return gcnew NativeObject(this); + } + REFrameworkNET::Method^ TypeDefinition::FindMethod(System::String^ name) { auto result = m_type->find_method(msclr::interop::marshal_as(name)); @@ -120,4 +125,10 @@ namespace REFrameworkNET { return gcnew ManagedObject(result); } + + bool TypeDefinition::TryInvokeMember(System::Dynamic::InvokeMemberBinder^ binder, array^ args, System::Object^% result) { + // Forward this onto NativeObject.TryInvokeMember (for static methods) + auto native = gcnew NativeObject(this); + return native->TryInvokeMember(binder, args, result); + } } \ No newline at end of file diff --git a/csharp-api/REFrameworkNET/TypeDefinition.hpp b/csharp-api/REFrameworkNET/TypeDefinition.hpp index 5b45a8de4..7aa81c3a7 100644 --- a/csharp-api/REFrameworkNET/TypeDefinition.hpp +++ b/csharp-api/REFrameworkNET/TypeDefinition.hpp @@ -8,6 +8,7 @@ namespace REFrameworkNET { ref class ManagedObject; +ref class NativeObject; ref class Method; ref class Field; ref class Property; @@ -22,7 +23,7 @@ public enum VMObjType { ValType = 5, }; -public ref class TypeDefinition : public System::IEquatable +public ref class TypeDefinition : public System::Dynamic::DynamicObject, public System::IEquatable { public: TypeDefinition(reframework::API::TypeDefinition* td) : m_type(td) {} @@ -32,6 +33,10 @@ public ref class TypeDefinition : public System::IEquatable return (reframework::API::TypeDefinition*)m_type; } + property NativeObject^ Statics { + NativeObject^ get(); + } + uint32_t GetIndex() { return m_type->get_index(); @@ -299,6 +304,11 @@ public ref class TypeDefinition : public System::IEquatable return m_type->create_instance_deprecated(); }*/ +// DynamicObject methods +public: + virtual bool TryInvokeMember(System::Dynamic::InvokeMemberBinder^ binder, array^ args, System::Object^% result) override; + +// IEquatable methods public: virtual bool Equals(System::Object^ other) override { if (System::Object::ReferenceEquals(this, other)) { diff --git a/csharp-api/test/Test/Test.cs b/csharp-api/test/Test/Test.cs index dc94c9579..b81c20096 100644 --- a/csharp-api/test/Test/Test.cs +++ b/csharp-api/test/Test/Test.cs @@ -260,6 +260,14 @@ public static void Main(REFrameworkNET.API api) { //REFrameworkNET.API.LogInfo("ProxyOptionData: " + proxyOptionData?.ToString() + ": " + proxyOptionData?.GetTypeDefinition()?.GetFullName()?.ToString()); + dynamic appdomainT = tdb.GetType("System.AppDomain"); + dynamic appdomain = appdomainT.get_CurrentDomain(); + dynamic assemblies = appdomain?.GetAssemblies(); + + foreach (dynamic assembly in assemblies) { + REFrameworkNET.API.LogInfo("Assembly: " + assembly.get_Location()?.ToString()); + } + } catch (Exception e) { REFrameworkNET.API.LogError(e.ToString());