Skip to content

Commit

Permalink
.NET: Add support for treating dynamics as IEnumerable
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Mar 21, 2024
1 parent c6d9106 commit 6583503
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 4 deletions.
9 changes: 8 additions & 1 deletion csharp-api/REFrameworkNET/Method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<System::Object^>^ 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<void*> args2{};

Expand Down
88 changes: 86 additions & 2 deletions csharp-api/REFrameworkNET/NativeObject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <cstdint>

#include "TypeDefinition.hpp"
#include "InvokeRet.hpp"

namespace REFrameworkNET {
ref class InvokeRet;
Expand All @@ -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;
}
Expand All @@ -41,6 +62,69 @@ public ref class NativeObject : public System::Dynamic::DynamicObject
bool HandleInvokeMember_Internal(System::String^ methodName, array<System::Object^>^ args, System::Object^% result);
virtual bool TryInvokeMember(System::Dynamic::InvokeMemberBinder^ binder, array<System::Object^>^ 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<System::Object^>{ position }, result)) {
return result;
}

return nullptr;
}
}

private:
int GetItemCount() {
//return nativeObject->Invoke("get_Count", gcnew array<System::Object^>{})->DWord;
System::Object^ result = nullptr;

if (nativeObject->HandleInvokeMember_Internal("get_Count", gcnew array<System::Object^>{}, result)) {
return (int)result;
}

if (nativeObject->HandleInvokeMember_Internal("get_Length", gcnew array<System::Object^>{}, result)) {
return (int)result;
}

return 0;
}
};

private:
void* m_object{};
TypeDefinition^ m_type{};
Expand Down
11 changes: 11 additions & 0 deletions csharp-api/REFrameworkNET/TypeDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string>(name));
Expand Down Expand Up @@ -120,4 +125,10 @@ namespace REFrameworkNET {

return gcnew ManagedObject(result);
}

bool TypeDefinition::TryInvokeMember(System::Dynamic::InvokeMemberBinder^ binder, array<System::Object^>^ args, System::Object^% result) {
// Forward this onto NativeObject.TryInvokeMember (for static methods)
auto native = gcnew NativeObject(this);
return native->TryInvokeMember(binder, args, result);
}
}
12 changes: 11 additions & 1 deletion csharp-api/REFrameworkNET/TypeDefinition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace REFrameworkNET {
ref class ManagedObject;
ref class NativeObject;
ref class Method;
ref class Field;
ref class Property;
Expand All @@ -22,7 +23,7 @@ public enum VMObjType {
ValType = 5,
};

public ref class TypeDefinition : public System::IEquatable<TypeDefinition^>
public ref class TypeDefinition : public System::Dynamic::DynamicObject, public System::IEquatable<TypeDefinition^>
{
public:
TypeDefinition(reframework::API::TypeDefinition* td) : m_type(td) {}
Expand All @@ -32,6 +33,10 @@ public ref class TypeDefinition : public System::IEquatable<TypeDefinition^>
return (reframework::API::TypeDefinition*)m_type;
}

property NativeObject^ Statics {
NativeObject^ get();
}

uint32_t GetIndex()
{
return m_type->get_index();
Expand Down Expand Up @@ -299,6 +304,11 @@ public ref class TypeDefinition : public System::IEquatable<TypeDefinition^>
return m_type->create_instance_deprecated();
}*/

// DynamicObject methods
public:
virtual bool TryInvokeMember(System::Dynamic::InvokeMemberBinder^ binder, array<System::Object^>^ args, System::Object^% result) override;

// IEquatable methods
public:
virtual bool Equals(System::Object^ other) override {
if (System::Object::ReferenceEquals(this, other)) {
Expand Down
8 changes: 8 additions & 0 deletions csharp-api/test/Test/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down

0 comments on commit 6583503

Please sign in to comment.