Skip to main content

il2cpp_bridge_rs/api/core/runtime/
caller.rs

1//! Raw IL2CPP method invocation with managed exception handling.
2
3use super::super::api;
4use crate::structs::core::hierarchy::object::Object;
5use std::ffi::c_void;
6
7/// Invokes an IL2CPP method using raw pointers.
8///
9/// This is the low-level escape hatch behind
10/// [`crate::structs::Method::call`](crate::structs::Method::call). Prefer that
11/// higher-level API unless you already have raw `MethodInfo`, object, and
12/// parameter pointers.
13///
14/// Managed exceptions are intercepted and returned as `Err(String)`.
15pub fn invoke_method(
16    method: *mut c_void,
17    obj: *mut c_void,
18    params: *const *mut c_void,
19) -> Result<*mut c_void, String> {
20    unsafe {
21        let mut exc: *mut c_void = std::ptr::null_mut();
22        let result = api::runtime_invoke(method, obj, params, &mut exc);
23
24        if !exc.is_null() {
25            let name_ptr = api::method_get_name(method);
26            let name = if !name_ptr.is_null() {
27                std::ffi::CStr::from_ptr(name_ptr).to_string_lossy()
28            } else {
29                std::borrow::Cow::Borrowed("unknown")
30            };
31
32            if name == "get_Message" {
33                return Err("Exception occurred while getting exception message".to_string());
34            }
35
36            let exc_class = api::object_get_class(exc);
37            let get_message_name = std::ffi::CString::new("get_Message").unwrap();
38            let get_message_method =
39                api::class_get_method_from_name(exc_class, get_message_name.as_ptr(), 0);
40
41            let message = if !get_message_method.is_null() {
42                let mut inner_exc: *mut c_void = std::ptr::null_mut();
43                let message_obj = api::runtime_invoke(
44                    get_message_method,
45                    exc,
46                    std::ptr::null_mut(),
47                    &mut inner_exc,
48                );
49
50                if !inner_exc.is_null() {
51                    "Exception thrown while getting exception message".to_string()
52                } else if !message_obj.is_null() {
53                    let il2cpp_string = message_obj as *mut crate::structs::Il2cppString;
54                    (*il2cpp_string).to_string().unwrap_or_default()
55                } else {
56                    "Exception message was null".to_string()
57                }
58            } else {
59                let exc_object = Object::from_ptr(exc);
60                exc_object.il2cpp_to_string()
61            };
62
63            return Err(format!(
64                "IL2CPP exception during invocation of '{}': {}",
65                name, message
66            ));
67        }
68
69        Ok(result)
70    }
71}