#pragma once #include #include // Forward declarations Mono struct MonoDomain; struct MonoAssembly; 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*); using mono_assembly_get_name_t = const void* (*)(MonoAssembly*); using mono_assembly_name_get_name_t = const char* (*)(const void*); 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; bool Initialize(std::shared_ptr 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. */ MonoAssembly* FindAssembly(const std::string& name); /** * @brief Finds a class in a loaded assembly by namespace and name. * @param assemblyName Name of the assembly (ex: "UnityEngine.CoreModule"). * @param namespaceName Namespace of the class (ex: "UnityEngine"). * @param className Name of the class (ex: "Screen"). * @return Pointer to the MonoClass, or nullptr if not found. */ MonoClass* FindClass(const std::string& assemblyName, const std::string& namespaceName, const std::string& className); /** * @brief Finds a method in a MonoClass and compiles it. * @param monoClass The MonoClass to search in. * @param methodName The method name (ex: "get_width"). * @param paramCount Number of parameters. * @return Compiled method address (uint8_t*), or nullptr if not found. */ 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 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* (*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; std::shared_ptr logger; /** * @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. */ static void FindAssemblyCallback(MonoAssembly* assembly, void* userData); };