forward_dll/
utils.rs

1use std::ffi::CString;
2
3use windows_sys::Win32::{
4    Foundation::{GetLastError, HMODULE},
5    System::LibraryLoader::{
6        FreeLibrary, GetModuleHandleExA, GetProcAddress, LoadLibraryA,
7        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
8    },
9};
10
11use crate::{ForwardError, ForwardResult};
12
13/// 通过调用 GetModuleHandleExA 增加引用计数。
14pub fn load_library_by_handle(inst: HMODULE) -> ForwardResult<HMODULE> {
15    let mut module_handle = 0;
16    let pin_success = unsafe {
17        GetModuleHandleExA(
18            GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
19            inst as *const u8,
20            &mut module_handle,
21        )
22    } != 0;
23    if !pin_success {
24        return Err(ForwardError::Win32Error("GetModuleHandleExA", unsafe {
25            GetLastError()
26        }));
27    }
28    Ok(module_handle)
29}
30
31/// LoadLibraryA 的包装。
32pub fn load_library(lib_filename: &str) -> ForwardResult<HMODULE> {
33    let module_name = CString::new(lib_filename).map_err(ForwardError::StringError)?;
34    let module_handle = unsafe { LoadLibraryA(module_name.as_ptr() as *const u8) };
35    if module_handle == 0 {
36        return Err(ForwardError::Win32Error("LoadLibraryA", unsafe {
37            GetLastError()
38        }));
39    }
40    Ok(module_handle)
41}
42
43/// FreeLibrary 的包装。
44pub fn free_library(inst: HMODULE) {
45    unsafe { FreeLibrary(inst) };
46}
47
48/// 取得指定函数名称的函数地址。
49pub fn get_proc_address_by_module(
50    inst: HMODULE,
51    proc_name: &str,
52) -> ForwardResult<unsafe extern "system" fn() -> isize> {
53    let proc_name = CString::new(proc_name).map_err(ForwardError::StringError)?;
54    unsafe {
55        GetProcAddress(inst, proc_name.as_ptr() as *const u8)
56            .ok_or_else(|| ForwardError::Win32Error("GetProcAddress", GetLastError()))
57    }
58}
59
60pub struct ForeignLibrary {
61    pub module_handle: HMODULE,
62}
63
64impl ForeignLibrary {
65    pub fn new(lib_name: &str) -> ForwardResult<Self> {
66        let module_handle = load_library(lib_name)?;
67        Ok(Self { module_handle })
68    }
69
70    pub fn get_proc_address(
71        &self,
72        proc_name: &str,
73    ) -> ForwardResult<unsafe extern "system" fn() -> isize> {
74        get_proc_address_by_module(self.module_handle, proc_name)
75    }
76
77    pub fn into_raw(self) -> HMODULE {
78        let handle = self.module_handle;
79        std::mem::forget(self);
80        handle
81    }
82}
83
84impl Drop for ForeignLibrary {
85    fn drop(&mut self) {
86        if self.module_handle != 0 {
87            free_library(self.module_handle);
88        }
89    }
90}