Skip to main content

Crate mono_rt

Crate mono_rt 

Source
Expand description

Dynamic bindings to the Mono runtime for Windows.

This crate attaches to a Mono runtime that is already loaded in the current process — it does not start a new JIT domain. The intended use case is process injection into Unity games and other Mono-hosted applications, where the Mono DLL is already mapped into memory before any code in this crate runs.

§Initialization

Before using any type in this crate, call init with the name of the Mono module as it appears in the host process. Common values:

  • "mono.dll" — Unity 2017 and earlier (legacy Mono)
  • "mono-2.0-bdwgc.dll" — Unity 2018+ (Boehm GC)
  • "mono-2.0.dll" — standalone Mono installations

init uses GetModuleHandleW internally, so the DLL must already be loaded; it does not call LoadLibrary.

§Threading model

Mono requires every thread that calls into the runtime to be registered with the garbage collector. Use MonoThreadGuard::attach to register the current thread before making any Mono API calls. The guard automatically deregisters the thread when dropped.

All handle types (MonoClass, MonoObject, …) are !Send + !Sync. They are bound to the thread on which they were obtained and cannot be moved to another thread without explicit unsafe code. This mirrors the per-thread attachment requirement: a handle is only valid on an attached thread, and the compiler prevents it from silently crossing that boundary.

See MonoThreadGuard for the full contract.

§Usage

use mono_rt::prelude::*;

// resolve exports from the already-loaded Mono DLL
mono_rt::init("mono-2.0-bdwgc.dll")?;

// attach the current thread — keep the guard live for the duration of all Mono work
let _guard = unsafe { MonoThreadGuard::attach()? };

// navigate the assembly graph
let image = MonoImage::find("Assembly-CSharp")?.expect("assembly not loaded");
let class = image.class_from_name("", "Player")?.expect("class not found");

// enumerate all fields and print their names and types
for field in class.fields()? {
    let name = field.name()?;
    let kind = field.mono_type()?.and_then(|t| t.kind().ok());
    println!("{name}: {kind:?}");
}

// read a field value directly from a live object
let hp_field = class.field("m_health")?.expect("field not found");
let offset = hp_field.offset()?;
// obj_ptr is a *mut c_void obtained from a previous MonoObject::as_ptr() call
// let hp: f32 = unsafe { mono_rt::read_field(obj_ptr, offset) };

Modules§

prelude
Commonly used types, re-exported as a single glob import.

Structs§

MonoArray
An opaque handle to a Mono runtime object.
MonoAssembly
An opaque handle to a Mono runtime object.
MonoClass
An opaque handle to a Mono runtime object.
MonoClassField
An opaque handle to a Mono runtime object.
MonoDomain
An opaque handle to a Mono runtime object.
MonoImage
An opaque handle to a Mono runtime object.
MonoMethod
An opaque handle to a Mono runtime object.
MonoObject
An opaque handle to a Mono runtime object.
MonoString
An opaque handle to a Mono runtime object.
MonoThread
An opaque handle to a Mono runtime object.
MonoThreadGuard
A RAII guard that keeps the current thread attached to the Mono runtime.
MonoType
An opaque handle to a Mono runtime object.
MonoVTable
An opaque handle to a Mono runtime object.

Enums§

MonoError
TypeKind
The type discriminant returned by mono_type_get_type, corresponding to MonoTypeEnum in the Mono source (mono/metadata/metadata.h).
Value
A typed Mono method argument.

Functions§

init
Resolves the Mono API by locating exports in the named module.
read_field
Reads a field of type T from a Mono object at the given byte offset.
write_field
Writes a value of type T into a field of a Mono object at the given byte offset.

Type Aliases§

MonoFunc
Result