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
13pub 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
31pub 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
43pub fn free_library(inst: HMODULE) {
45 unsafe { FreeLibrary(inst) };
46}
47
48pub 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}