tproxy_config/
fn_holder.rs

1#![allow(dead_code)]
2
3pub trait FnCast: Copy {}
4
5pub struct FnHolder<F: FnCast> {
6    _lib: ::libloading::Library,
7    pub func: F,
8}
9
10unsafe impl<F: FnCast> Send for FnHolder<F> {}
11unsafe impl<F: FnCast> Sync for FnHolder<F> {}
12
13pub fn load_function<F: FnCast>(module_name: &str, function_name: &str) -> Option<FnHolder<F>> {
14    unsafe {
15        let function_name_cstr = std::ffi::CString::new(function_name).ok()?;
16        let _lib = ::libloading::Library::new(module_name).ok()?;
17        let func: F = _lib.get(function_name_cstr.to_bytes_with_nul()).map(|sym| *sym).ok()?;
18        Some(FnHolder { _lib, func })
19    }
20}
21
22#[macro_export]
23macro_rules! define_fn_dynamic_load {
24    ($fn_type:ident, $fn_signature:ty, $static_var:ident, $load_fn:ident, $module_name:expr, $fn_name:expr) => {
25        pub type $fn_type = $fn_signature;
26
27        impl $crate::fn_holder::FnCast for $fn_type {}
28
29        #[allow(non_upper_case_globals)]
30        static $static_var: std::sync::OnceLock<Option<$crate::fn_holder::FnHolder<$fn_type>>> = std::sync::OnceLock::new();
31
32        #[allow(non_snake_case)]
33        pub fn $load_fn() -> Option<$fn_type> {
34            $static_var
35                .get_or_init(|| $crate::fn_holder::load_function($module_name, $fn_name))
36                .as_ref()
37                .map(|fn_holder| fn_holder.func)
38        }
39    };
40}
41
42/*
43// usage
44use windows_sys::Win32::Foundation::BOOL;
45define_fn_dynamic_load!(
46    ProcessPrngDeclare,
47    unsafe extern "system" fn(pbdata: *mut u8, cbdata: usize) -> BOOL,
48    PROCESS_PRNG,
49    ProcessPrng,
50    "bcryptprimitives.dll",
51    "ProcessPrng"
52);
53let func = ProcessPrng().ok_or("Failed to load function ProcessPrng")?;
54*/