skyline/
nro.rs

1use core::fmt;
2use crate::nn::ro;
3
4pub type Callback = extern "Rust" fn(&NroInfo);
5
6/// An error representing the NRO hook plugin not successfully being linked against
7#[derive(Debug, Clone, Copy)]
8pub struct NroHookPluginMissing;
9
10#[allow(improper_ctypes)]
11extern "C" {
12    fn add_nro_load_hook(callback: Callback);
13    fn add_nro_unload_hook(callback: Callback);
14}
15
16/// A function to allow adding a hook for immediately after an NRO has been loaded.
17///
18/// **Note:** Requires the NRO hook plugin. Will return an error otherwise.
19pub fn add_hook(callback: Callback) -> Result<(), NroHookPluginMissing> {
20    // Removed the null check on the function because function pointers are not nullable. Should probably get them through the nnsdk symbol resolver for this purpose.
21        unsafe { add_nro_load_hook(callback); }
22        Ok(())
23
24}
25
26pub fn add_unload_hook(callback: Callback) -> Result<(), NroHookPluginMissing> {
27    unsafe { add_nro_unload_hook(callback); }
28    Ok(())
29}
30
31/// A struct to hold information related to the NRO being loaded
32#[repr(C)]
33#[non_exhaustive]
34pub struct NroInfo<'a> {
35    pub name: &'a str,
36    pub module: &'a mut ro::Module
37}
38
39impl<'a> NroInfo<'a> {
40    /// A function only to be used by nro_hook in order to construct NroInfos. Since fields may be
41    /// added, this API is subject to change.
42    #[cfg(feature = "nro_internal")]
43    pub fn new(name: &'a str, module: &'a mut ro::Module) -> Self {
44        Self { name, module }
45    }
46}
47
48impl fmt::Display for NroHookPluginMissing {
49    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50        write!(f, "The NRO hook plugin could not be found and is required to add NRO hooks. Make sure hook_nro.nro is installed.")
51    }
52}