Files
ReshadePluginsCore/libs/Unity/MonoLoader.cpp

176 lines
7.4 KiB
C++
Raw Normal View History

2026-02-22 11:30:19 +01:00
#include "MonoLoader.hpp"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
HMODULE MonoLoader::WaitForMono(const char* monoName) {
HMODULE mono = nullptr;
while (!mono) {
mono = GetModuleHandleA(monoName);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
return mono;
}
bool MonoLoader::Initialize(std::shared_ptr<spdlog::logger> log, const char* monoName) {
if (log) logger = log;
HMODULE mono = WaitForMono(monoName);
if (!mono) {
logger->error("Mono module not found.");
return false;
}
logger->info("Mono DLL found at {:p}", (void*)mono);
2026-02-27 22:50:18 +01:00
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");
2026-02-22 11:30:19 +01:00
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");
mono_class_get_methods = (mono_class_get_methods_t)GetProcAddress(mono, "mono_class_get_methods");
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");
2026-02-27 22:50:18 +01:00
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 (!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) {
2026-02-22 11:30:19 +01:00
logger->error("Failed to resolve one or more Mono exports.");
return false;
}
2026-02-27 22:50:18 +01:00
g_monoDomain = mono_get_root_domain();
2026-02-22 11:30:19 +01:00
if (!g_monoDomain) {
logger->error("Mono root domain is null.");
return false;
}
2026-02-27 22:50:18 +01:00
mono_thread_attach(g_monoDomain);
2026-02-22 11:30:19 +01:00
logger->info("Attached to Mono domain {:p}", (void*)g_monoDomain);
return true;
}
struct FindAssemblyData {
MonoLoader* loader;
const std::string* targetName;
MonoAssembly* result = nullptr;
};
void MonoLoader::FindAssemblyCallback(MonoAssembly* assembly, void* userData) {
auto data = reinterpret_cast<FindAssemblyData*>(userData);
if (!assembly || !data || !data->targetName) return;
const void* nameStruct = data->loader->mono_assembly_get_name(assembly);
const char* nameCStr = data->loader->mono_assembly_name_get_name(nameStruct);
if (nameCStr && *data->targetName == nameCStr) {
data->result = assembly;
}
}
MonoAssembly* MonoLoader::FindAssembly(const std::string& name) {
if (!mono_assembly_foreach || !mono_assembly_get_name || !mono_assembly_name_get_name) {
logger->error("Mono exports not resolved, cannot enumerate assemblies.");
return nullptr;
}
FindAssemblyData data;
data.loader = this;
data.targetName = &name;
data.result = nullptr;
mono_assembly_foreach(MonoLoader::FindAssemblyCallback, &data);
return data.result;
}
MonoClass* MonoLoader::FindClass(const std::string& assemblyName, const std::string& namespaceName, const std::string& className) {
MonoAssembly* assembly = FindAssembly(assemblyName);
if (!assembly) return nullptr;
2026-02-27 22:50:18 +01:00
MonoImage* image = mono_assembly_get_image(assembly);
2026-02-22 11:30:19 +01:00
if (!image) return nullptr;
2026-02-27 22:50:18 +01:00
return mono_class_from_name(image, namespaceName.c_str(), className.c_str());
2026-02-22 11:30:19 +01:00
}
uint8_t* MonoLoader::GetCompiledMethod(MonoClass* monoClass, const std::string& methodName, int paramCount) {
if (!monoClass) return nullptr;
2026-02-27 22:50:18 +01:00
MonoMethod* method = mono_class_get_method_from_name(monoClass, methodName.c_str(), paramCount);
if (!method) return nullptr;
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) {
2026-02-22 11:30:19 +01:00
if (!method) return nullptr;
2026-02-27 22:50:18 +01:00
MonoThread* thread = AttachCurrentThread();
if (!thread) return nullptr;
MonoObject* invoke = mono_runtime_invoke(method, obj, params, exception);
DetachCurrentThread(thread);
return invoke;
2026-02-22 11:30:19 +01:00
}
void MonoLoader::DumpMethods(MonoClass* monoClass, std::shared_ptr<spdlog::logger> logger) {
if (!monoClass) {
logger->error("DumpMethods: monoClass is null.");
return;
}
if (!g_monoDomain) {
logger->error("DumpMethods: Mono domain is null.");
return;
}
2026-02-27 22:50:18 +01:00
mono_thread_attach(g_monoDomain);
2026-02-22 11:30:19 +01:00
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.");
return;
}
logger->info("---- Dumping methods ----");
void* iter = nullptr;
MonoMethod* method = nullptr;
while ((method = mono_class_get_methods(monoClass, &iter)) != nullptr) {
const char* name = mono_method_get_name(method);
MonoMethodSignature* sig = mono_method_signature(method);
uint32_t paramCount = 0;
if (sig) paramCount = mono_signature_get_param_count(sig);
logger->info("Method: {} | Params: {}", name ? name : "null", paramCount);
}
logger->info("-------------------------");
}