1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use crate::bindings::{mono_object_unbox, MonoObject};
use std::{
    error::Error,
    ffi::{c_void, CString},
    ptr::null_mut,
};

pub mod array;
pub mod assembly;
pub mod bindings;
pub mod class;
pub mod domain;
pub mod exception;
pub mod field;
pub mod image;
pub mod method;
pub mod object;
pub mod string;
pub mod thread;

type MonoResult<T> = Result<T, Box<dyn Error>>;

pub trait AsRawVoid {
    fn as_raw_void(self) -> *mut c_void;
}

pub trait Unbox {
    fn unbox(object: *mut MonoObject) -> Self;
}

pub trait MonoAutoMarker {}
impl MonoAutoMarker for bool {}
impl MonoAutoMarker for usize {}
impl MonoAutoMarker for isize {}
impl MonoAutoMarker for u8 {}
impl MonoAutoMarker for i8 {}
impl MonoAutoMarker for u16 {}
impl MonoAutoMarker for i16 {}
impl MonoAutoMarker for u32 {}
impl MonoAutoMarker for i32 {}
impl MonoAutoMarker for u64 {}
impl MonoAutoMarker for i64 {}
impl MonoAutoMarker for u128 {}
impl MonoAutoMarker for i128 {}
impl MonoAutoMarker for f32 {}
impl MonoAutoMarker for f64 {}

impl<T> AsRawVoid for T
where
    T: MonoAutoMarker,
{
    fn as_raw_void(self) -> *mut c_void {
        Box::into_raw(Box::new(self)) as *mut _ as *mut c_void
    }
}

impl<T> Unbox for T
where
    T: MonoAutoMarker + Copy,
{
    fn unbox(object: *mut MonoObject) -> Self {
        let val_raw_ptr = unsafe { mono_object_unbox(object) as *mut _ as *mut T };
        unsafe { *val_raw_ptr }
    }
}

impl AsRawVoid for &str {
    fn as_raw_void(self) -> *mut c_void {
        let cstr = Box::new(CString::new(self).unwrap());
        let mut cstr_ptr = cstr.as_ptr();
        Box::into_raw(cstr);
        &mut cstr_ptr as *mut _ as *mut c_void
    }
}

impl AsRawVoid for String {
    fn as_raw_void(self) -> *mut c_void {
        let cstr = Box::new(CString::new(self.as_str()).unwrap());
        let mut cstr_ptr = cstr.as_ptr();
        Box::into_raw(cstr);
        &mut cstr_ptr as *mut _ as *mut c_void
    }
}

impl<T> AsRawVoid for Option<T>
where
    T: AsRawVoid,
{
    fn as_raw_void(self) -> *mut c_void {
        match self {
            Some(t) => t.as_raw_void(),
            None => null_mut() as *mut c_void,
        }
    }
}


#[cfg(test)]
mod tests {
    use crate::{bindings::*, domain::Domain, MonoResult};
    use std::{
        ffi::{c_void, CString},
        ptr::null_mut,
    };

    #[test]
    fn test() -> MonoResult<()> {
        println!("Creating Domain");
        let domain = Domain::new("Default")?;

        println!("Opening Assembly");
        let assembly = domain.open_assembly("Test.dll")?;

        println!("Getting Image");
        let image = assembly.get_image()?;

        println!("Getting Class");
        let class = image.get_class_by_name("TestNS", "TestClass")?;

        println!("Creating Object");
        let object = class.create_object()?;

        println!("Calling Constructor");
        object.construct(None)?;

        println!("Getting Field");
        let field = object.get_field_by_name("TestField")?;

        println!("Getting Field Value");
        let value_object = unsafe {
            mono_field_get_value_object(domain.mono_domain, field.mono_field, object.mono_object)
        };
        let value_string_object = value_object as *mut MonoString;
        let value_string = unsafe { mono_string_to_utf8(value_string_object) };
        let value_string = unsafe { CString::from_raw(value_string) };

        println!("Value: {}", &*value_string.to_string_lossy());

        println!("Getting MethodDesc");
        let method_name = CString::new("TestClass:getTestField()").unwrap();
        let method_decs = unsafe { mono_method_desc_new(method_name.as_ptr(), 0) };
        let method = unsafe { mono_method_desc_search_in_class(method_decs, class.mono_class) };

        println!("Calling Method");
        let result_object = unsafe {
            mono_runtime_invoke(
                method,
                object.mono_object as *mut c_void,
                null_mut(),
                null_mut(),
            )
        };
        let result_string_object = result_object as *mut MonoString;
        let result_string = unsafe { mono_string_to_utf8(result_string_object) };
        let result_string = unsafe { CString::from_raw(result_string) };

        println!("Result: {}", &*result_string.to_string_lossy());

        Ok(())
    }
}