Add methods to the SDK

This commit is contained in:
2026-02-27 22:50:18 +01:00
parent 0e1bfcb9c8
commit 711da7f636
2 changed files with 114 additions and 43 deletions

View File

@@ -21,13 +21,13 @@ bool MonoLoader::Initialize(std::shared_ptr<spdlog::logger> log, const char* mon
}
logger->info("Mono DLL found at {:p}", (void*)mono);
g_mono_get_root_domain = (MonoDomain * (*)())GetProcAddress(mono, "mono_get_root_domain");
g_mono_thread_attach = (void(*)(MonoDomain*))GetProcAddress(mono, "mono_thread_attach");
g_mono_domain_assembly_open = (MonoAssembly * (*)(MonoDomain*, const char*))GetProcAddress(mono, "mono_domain_assembly_open");
g_mono_assembly_get_image = (MonoImage * (*)(MonoAssembly*))GetProcAddress(mono, "mono_assembly_get_image");
g_mono_class_from_name = (MonoClass * (*)(MonoImage*, const char*, const char*))GetProcAddress(mono, "mono_class_from_name");
g_mono_class_get_method_from_name = (MonoMethod * (*)(MonoClass*, const char*, int))GetProcAddress(mono, "mono_class_get_method_from_name");
g_mono_compile_method = (void* (*)(MonoMethod*))GetProcAddress(mono, "mono_compile_method");
mono_get_root_domain = (MonoDomain * (*)())GetProcAddress(mono, "mono_get_root_domain");
mono_thread_attach = (MonoThread * (*)(MonoDomain*))GetProcAddress(mono, "mono_thread_attach");
mono_domain_assembly_open = (MonoAssembly * (*)(MonoDomain*, const char*))GetProcAddress(mono, "mono_domain_assembly_open");
mono_assembly_get_image = (MonoImage * (*)(MonoAssembly*))GetProcAddress(mono, "mono_assembly_get_image");
mono_class_from_name = (MonoClass * (*)(MonoImage*, const char*, const char*))GetProcAddress(mono, "mono_class_from_name");
mono_class_get_method_from_name = (MonoMethod * (*)(MonoClass*, const char*, int))GetProcAddress(mono, "mono_class_get_method_from_name");
mono_compile_method = (void* (*)(MonoMethod*))GetProcAddress(mono, "mono_compile_method");
mono_assembly_foreach = (void(*)(void(*)(MonoAssembly*, void*), void*))GetProcAddress(mono, "mono_assembly_foreach");
mono_assembly_get_name = (mono_assembly_get_name_t)GetProcAddress(mono, "mono_assembly_get_name");
mono_assembly_name_get_name = (mono_assembly_name_get_name_t)GetProcAddress(mono, "mono_assembly_name_get_name");
@@ -35,22 +35,28 @@ bool MonoLoader::Initialize(std::shared_ptr<spdlog::logger> log, const char* mon
mono_method_get_name = (mono_method_get_name_t)GetProcAddress(mono, "mono_method_get_name");
mono_method_signature = (mono_method_signature_t)GetProcAddress(mono, "mono_method_signature");
mono_signature_get_param_count = (mono_signature_get_param_count_t)GetProcAddress(mono, "mono_signature_get_param_count");
mono_class_get_field_from_name = (mono_class_get_field_from_name_t)GetProcAddress(mono, "mono_class_get_field_from_name");
mono_runtime_invoke = (mono_runtime_invoke_t) GetProcAddress(mono, "mono_runtime_invoke");
mono_field_get_offset = (mono_field_get_offset_t)GetProcAddress(mono, "mono_field_get_offset");
mono_field_set_value = (mono_field_set_value_t)GetProcAddress(mono, "mono_field_set_value");
mono_field_get_value = (mono_field_get_value_t)GetProcAddress(mono, "mono_field_get_value");
if (!g_mono_get_root_domain || !g_mono_thread_attach || !g_mono_domain_assembly_open ||
!g_mono_assembly_get_image || !g_mono_class_from_name || !g_mono_class_get_method_from_name ||
!g_mono_compile_method || !mono_assembly_foreach || !mono_assembly_get_name || !mono_assembly_name_get_name ||
!mono_class_get_methods || !mono_method_get_name || !mono_method_signature || !mono_signature_get_param_count) {
if (!mono_get_root_domain || !mono_thread_attach || !mono_domain_assembly_open || !mono_assembly_get_image ||
!mono_class_from_name || !mono_class_get_method_from_name || !mono_compile_method || !mono_assembly_foreach ||
!mono_assembly_get_name || !mono_assembly_name_get_name || !mono_class_get_methods || !mono_method_get_name ||
!mono_method_signature || !mono_signature_get_param_count || !mono_class_get_field_from_name ||
!mono_runtime_invoke || !mono_field_get_offset || !mono_field_set_value || !mono_field_get_value) {
logger->error("Failed to resolve one or more Mono exports.");
return false;
}
g_monoDomain = g_mono_get_root_domain();
g_monoDomain = mono_get_root_domain();
if (!g_monoDomain) {
logger->error("Mono root domain is null.");
return false;
}
g_mono_thread_attach(g_monoDomain);
mono_thread_attach(g_monoDomain);
logger->info("Attached to Mono domain {:p}", (void*)g_monoDomain);
return true;
}
@@ -92,17 +98,44 @@ MonoClass* MonoLoader::FindClass(const std::string& assemblyName, const std::str
MonoAssembly* assembly = FindAssembly(assemblyName);
if (!assembly) return nullptr;
MonoImage* image = g_mono_assembly_get_image(assembly);
MonoImage* image = mono_assembly_get_image(assembly);
if (!image) return nullptr;
return g_mono_class_from_name(image, namespaceName.c_str(), className.c_str());
return mono_class_from_name(image, namespaceName.c_str(), className.c_str());
}
uint8_t* MonoLoader::GetCompiledMethod(MonoClass* monoClass, const std::string& methodName, int paramCount) {
if (!monoClass) return nullptr;
MonoMethod* method = g_mono_class_get_method_from_name(monoClass, methodName.c_str(), paramCount);
MonoMethod* method = mono_class_get_method_from_name(monoClass, methodName.c_str(), paramCount);
if (!method) return nullptr;
return (uint8_t*)g_mono_compile_method(method);
return (uint8_t*)mono_compile_method(method);
}
MonoThread* MonoLoader::AttachCurrentThread() {
MonoThread* monoThread = mono_thread_attach(mono_get_root_domain());
if (!monoThread) return nullptr;
return monoThread;
}
void MonoLoader::DetachCurrentThread(MonoThread* thread) {
if (!thread || !mono_thread_detach) return;
mono_thread_detach(thread);
}
MonoMethod* MonoLoader::GetMethod(MonoClass* monoClass, const std::string& methodName, int paramCount) {
if (!monoClass) return nullptr;
MonoMethod* method = mono_class_get_method_from_name(monoClass, methodName.c_str(), paramCount);
if (!method) return nullptr;
return method;
}
MonoObject* MonoLoader::InvokeMethod(MonoMethod* method, MonoObject* obj, void** params, MonoObject** exception) {
if (!method) return nullptr;
MonoThread* thread = AttachCurrentThread();
if (!thread) return nullptr;
MonoObject* invoke = mono_runtime_invoke(method, obj, params, exception);
DetachCurrentThread(thread);
return invoke;
}
void MonoLoader::DumpMethods(MonoClass* monoClass, std::shared_ptr<spdlog::logger> logger) {
@@ -116,7 +149,7 @@ void MonoLoader::DumpMethods(MonoClass* monoClass, std::shared_ptr<spdlog::logge
return;
}
g_mono_thread_attach(g_monoDomain);
mono_thread_attach(g_monoDomain);
if (!mono_class_get_methods || !mono_method_get_name || !mono_method_signature || !mono_signature_get_param_count) {
logger->error("DumpMethods: Required Mono exports not resolved.");

View File

@@ -9,6 +9,9 @@ struct MonoImage;
struct MonoClass;
struct MonoMethod;
struct MonoMethodSignature;
struct MonoClassField;
struct MonoObject;
struct MonoThread;
// Typedefs pour les exports Mono
using mono_assembly_foreach_t = void(*)(void(*)(MonoAssembly*, void*), void*);
@@ -18,32 +21,25 @@ using mono_class_get_methods_t = MonoMethod * (*)(MonoClass*, void**);
using mono_method_get_name_t = const char* (*)(MonoMethod*);
using mono_method_signature_t = MonoMethodSignature * (*)(MonoMethod*);
using mono_signature_get_param_count_t = uint32_t(*)(MonoMethodSignature*);
using mono_class_get_field_from_name_t = MonoClassField * (*)(MonoClass*, const char*);
using mono_runtime_invoke_t = MonoObject * (*)(MonoMethod*, void*, void**, MonoObject**);
using mono_field_get_offset_t = int (*)(MonoClassField*);
using mono_field_set_value_t = void (*)(MonoObject*, MonoClassField*, void*);
using mono_field_get_value_t = void (*)(MonoObject*, MonoClassField*, void*);
class MonoLoader {
public:
MonoLoader() = default;
~MonoLoader() = default;
/**
* @brief Callback used during Mono assembly enumeration.
*
* This function is passed to `mono_assembly_foreach` and checks each loaded assembly
* to find the one matching a specific name (provided via userData).
* Can be used to initialize pointers to target assemblies.
*
* @param assembly Pointer to the current assembly.
* @param userData User data passed to `mono_assembly_foreach`, typically a structure
* containing the target name and a location to store the result.
*/
bool Initialize(std::shared_ptr<spdlog::logger> log = nullptr, const char* monoName = "mono-2.0-bdwgc.dll");
MonoDomain* GetDomain() const { return g_monoDomain; }
/**
* @brief Finds a Mono assembly by its name.
*
* This function iterates over all loaded assemblies in the Mono domain and
* returns a pointer to the assembly matching the given name.
*
* @param name Name of the assembly to search for.
* @return MonoAssembly* Pointer to the found assembly, or nullptr if not found.
*/
@@ -67,24 +63,70 @@ public:
*/
uint8_t* GetCompiledMethod(MonoClass* monoClass, const std::string& methodName, int paramCount);
/**
* @brief Attach the current thread to the Mono domain (required before invoking methods).
* @return MonoThread* pointer to the attached thread.
*/
MonoThread* AttachCurrentThread();
/**
* @brief Detach the current thread from the Mono runtime.
* Should be called if AttachCurrentThread() was used on a manually created thread.
* For the main thread, Mono typically handles detachment automatically.
* @param thread Pointer to the MonoThread previously returned by AttachCurrentThread().
*/
void DetachCurrentThread(MonoThread* thread);
/**
* @brief Retrieve a method from a Mono class by name and parameter count.
* @param monoClass The MonoClass to search in.
* @param methodName The name of the method.
* @param paramCount Number of parameters (use -1 for any).
* @return MonoMethod* pointer, or nullptr if not found.
*/
MonoMethod* GetMethod(MonoClass* monoClass, const std::string& methodName, int paramCount);
/**
* @brief Invoke a Mono method safely.
* @param method MonoMethod* to invoke.
* @param obj MonoObject* instance, or nullptr for static methods.
* @param params Array of pointers to arguments, or nullptr if none.
* @param exception Optional pointer to MonoObject* to catch exceptions.
* @return MonoObject* result of the method call, or nullptr.
*/
MonoObject* InvokeMethod(MonoMethod* method, MonoObject* obj, void** params = nullptr, MonoObject** exception = nullptr);
/**
* @brief Dump all methods of a MonoClass to the log.
* Iterates over all methods defined in the given MonoClass and logs their
* names and signatures. Useful for debugging or exploring Mono assemblies.
* @param monoClass Pointer to the MonoClass whose methods will be dumped.
* @param log Optional logger to output the method information. If nullptr,
* no logging is performed.
*/
void DumpMethods(MonoClass* monoClass, std::shared_ptr<spdlog::logger> log = nullptr);
// Exports
mono_assembly_foreach_t mono_assembly_foreach = nullptr;
mono_assembly_get_name_t mono_assembly_get_name = nullptr;
mono_assembly_name_get_name_t mono_assembly_name_get_name = nullptr;
MonoDomain* (*g_mono_get_root_domain)() = nullptr;
void (*g_mono_thread_attach)(MonoDomain*) = nullptr;
MonoAssembly* (*g_mono_domain_assembly_open)(MonoDomain*, const char*) = nullptr;
MonoImage* (*g_mono_assembly_get_image)(MonoAssembly*) = nullptr;
MonoClass* (*g_mono_class_from_name)(MonoImage*, const char*, const char*) = nullptr;
MonoMethod* (*g_mono_class_get_method_from_name)(MonoClass*, const char*, int) = nullptr;
void* (*g_mono_compile_method)(MonoMethod*) = nullptr;
MonoDomain* (*mono_get_root_domain)() = nullptr;
MonoThread* (*mono_thread_attach)(MonoDomain*) = nullptr;
void* (*mono_thread_detach)(MonoThread*) = nullptr;
MonoAssembly* (*mono_domain_assembly_open)(MonoDomain*, const char*) = nullptr;
MonoImage* (*mono_assembly_get_image)(MonoAssembly*) = nullptr;
MonoClass* (*mono_class_from_name)(MonoImage*, const char*, const char*) = nullptr;
MonoMethod* (*mono_class_get_method_from_name)(MonoClass*, const char*, int) = nullptr;
void* (*mono_compile_method)(MonoMethod*) = nullptr;
mono_class_get_methods_t mono_class_get_methods = nullptr;
mono_method_get_name_t mono_method_get_name = nullptr;
mono_method_signature_t mono_method_signature = nullptr;
mono_signature_get_param_count_t mono_signature_get_param_count = nullptr;
mono_class_get_field_from_name_t mono_class_get_field_from_name = nullptr;
mono_runtime_invoke_t mono_runtime_invoke = nullptr;
mono_field_get_offset_t mono_field_get_offset = nullptr;
mono_field_set_value_t mono_field_set_value = nullptr;
mono_field_get_value_t mono_field_get_value = nullptr;
private:
MonoDomain* g_monoDomain = nullptr;
@@ -92,22 +134,18 @@ private:
/**
* @brief Waits for the Mono module to be loaded in the process and returns its handle.
*
* This function loops every 200 ms until the "mono-2.0-bdwgc.dll" module
* is present in the current process. Useful to ensure that Mono is initialized
* before resolving its exports.
*
* @return HMODULE Handle of the Mono module, or nullptr if not found (practically never).
*/
HMODULE WaitForMono(const char* monoName);
/**
* @brief Callback used during Mono assembly enumeration.
*
* This function is passed to `mono_assembly_foreach` and checks each loaded assembly
* to find the one matching a specific name (provided via userData).
* Can be used to initialize pointers to target assemblies.
*
* @param assembly Pointer to the current assembly.
* @param userData User data passed to `mono_assembly_foreach`, typically a structure
* containing the target name and a location to store the result.