#[cfg(all(libloading_docs, not(windows)))]
mod windows_imports {}
#[cfg(any(not(libloading_docs), windows))]
mod windows_imports {
use super::{BOOL, DWORD, FARPROC, HANDLE, HMODULE};
windows_link::link!("kernel32.dll" "system" fn GetLastError() -> DWORD);
windows_link::link!("kernel32.dll" "system" fn SetThreadErrorMode(new_mode: DWORD, old_mode: *mut DWORD) -> BOOL);
windows_link::link!("kernel32.dll" "system" fn GetModuleHandleExW(flags: u32, module_name: *const u16, module: *mut HMODULE) -> BOOL);
windows_link::link!("kernel32.dll" "system" fn FreeLibrary(module: HMODULE) -> BOOL);
windows_link::link!("kernel32.dll" "system" fn LoadLibraryExW(filename: *const u16, file: HANDLE, flags: DWORD) -> HMODULE);
windows_link::link!("kernel32.dll" "system" fn GetModuleFileNameW(module: HMODULE, filename: *mut u16, size: DWORD) -> DWORD);
windows_link::link!("kernel32.dll" "system" fn GetProcAddress(module: HMODULE, procname: *const u8) -> FARPROC);
}
use self::windows_imports::*;
use crate::as_filename::AsFilename;
use crate::as_symbol_name::AsSymbolName;
use crate::util::ensure_compatible_types;
use core::{fmt, marker, mem, ptr};
pub struct Library(HMODULE);
unsafe impl Send for Library {}
unsafe impl Sync for Library {}
impl Library {
#[inline]
pub unsafe fn new(filename: impl AsFilename) -> Result<Library, crate::Error> {
Library::load_with_flags(filename, 0)
}
pub fn this() -> Result<Library, crate::Error> {
unsafe {
let mut handle: HMODULE = 0;
with_get_last_error(
|source| crate::Error::GetModuleHandleExW { source },
|| {
let result = GetModuleHandleExW(0, ptr::null_mut(), &mut handle);
if result == 0 {
None
} else {
Some(Library(handle))
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
}
}
pub fn open_already_loaded(filename: impl AsFilename) -> Result<Library, crate::Error> {
filename.windows_filename(|windows_filename| {
unsafe {
let mut handle: HMODULE = 0;
with_get_last_error(
|source| crate::Error::GetModuleHandleExW { source },
|| {
let result = GetModuleHandleExW(0, windows_filename, &mut handle);
if result == 0 {
None
} else {
Some(Library(handle))
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
}
})
}
pub unsafe fn load_with_flags(
filename: impl AsFilename,
flags: LOAD_LIBRARY_FLAGS,
) -> Result<Library, crate::Error> {
filename.windows_filename(|windows_filename| {
let _guard = ErrorModeGuard::new();
with_get_last_error(
|source| crate::Error::LoadLibraryExW { source },
|| {
let handle = LoadLibraryExW(windows_filename, 0, flags);
if handle == 0 {
None
} else {
Some(Library(handle))
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::LoadLibraryExWUnknown))
})
}
pub fn pin(&self) -> Result<(), crate::Error> {
const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 0x1;
const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x4;
unsafe {
let mut handle: HMODULE = 0;
with_get_last_error(
|source| crate::Error::GetModuleHandleExW { source },
|| {
let result = GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
self.0 as *const u16,
&mut handle,
);
if result == 0 {
None
} else {
Some(())
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
}
}
pub unsafe fn get<T>(&self, symbol: impl AsSymbolName) -> Result<Symbol<T>, crate::Error> {
ensure_compatible_types::<T, FARPROC>()?;
symbol.symbol_name(|windows_symbol| {
with_get_last_error(
|source| crate::Error::GetProcAddress { source },
|| {
let symbol = GetProcAddress(self.0, windows_symbol.cast());
if symbol.is_none() {
None
} else {
Some(Symbol {
pointer: symbol,
pd: marker::PhantomData,
})
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
})
}
pub unsafe fn get_ordinal<T>(&self, ordinal: u16) -> Result<Symbol<T>, crate::Error> {
ensure_compatible_types::<T, FARPROC>()?;
with_get_last_error(
|source| crate::Error::GetProcAddress { source },
|| {
let ordinal = ordinal as usize as *const _;
let symbol = GetProcAddress(self.0, ordinal);
if symbol.is_none() {
None
} else {
Some(Symbol {
pointer: symbol,
pd: marker::PhantomData,
})
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
}
pub fn into_raw(self) -> HMODULE {
let handle = self.0;
mem::forget(self);
handle
}
pub unsafe fn from_raw(handle: HMODULE) -> Library {
Library(handle)
}
pub fn close(self) -> Result<(), crate::Error> {
let result = with_get_last_error(
|source| crate::Error::FreeLibrary { source },
|| {
if unsafe { FreeLibrary(self.0) == 0 } {
None
} else {
Some(())
}
},
)
.map_err(|e| e.unwrap_or(crate::Error::FreeLibraryUnknown));
mem::forget(self);
result
}
}
impl Drop for Library {
fn drop(&mut self) {
unsafe {
FreeLibrary(self.0);
}
}
}
impl fmt::Debug for Library {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
let mut buf = mem::MaybeUninit::<[mem::MaybeUninit<u16>; 1024]>::uninit().assume_init();
let len = GetModuleFileNameW(self.0, buf[..].as_mut_ptr().cast(), 1024) as usize;
if len == 0 {
f.write_fmt(format_args!("Library@{:#x}", self.0))
} else {
let string: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(
&*(&buf[..len] as *const [_] as *const [u16]),
);
f.write_fmt(format_args!("Library@{:#x} from {:?}", self.0, string))
}
}
}
#[cfg(not(feature = "std"))]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("Library@{:#x}", self.0))
}
}
pub struct Symbol<T> {
pointer: FARPROC,
pd: marker::PhantomData<T>,
}
impl<T> Symbol<T> {
pub fn into_raw(self) -> FARPROC {
self.pointer
}
pub fn as_raw_ptr(self) -> *mut core::ffi::c_void {
self.pointer
.map(|raw| raw as *mut core::ffi::c_void)
.unwrap_or(ptr::null_mut())
}
}
impl<T> Symbol<Option<T>> {
pub fn lift_option(self) -> Option<Symbol<T>> {
if self.pointer.is_none() {
None
} else {
Some(Symbol {
pointer: self.pointer,
pd: marker::PhantomData,
})
}
}
}
unsafe impl<T: Send> Send for Symbol<T> {}
unsafe impl<T: Sync> Sync for Symbol<T> {}
impl<T> Clone for Symbol<T> {
fn clone(&self) -> Symbol<T> {
Symbol { ..*self }
}
}
impl<T> core::ops::Deref for Symbol<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*((&self.pointer) as *const FARPROC as *const T) }
}
}
impl<T> fmt::Debug for Symbol<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.pointer {
None => f.write_str("Symbol@0x0"),
Some(ptr) => f.write_fmt(format_args!("Symbol@{:p}", ptr as *const ())),
}
}
}
struct ErrorModeGuard(DWORD);
impl ErrorModeGuard {
#[allow(clippy::if_same_then_else)]
fn new() -> Option<ErrorModeGuard> {
unsafe {
let mut previous_mode = 0;
if SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 {
None
} else if previous_mode == SEM_FAILCRITICALERRORS {
None
} else {
Some(ErrorModeGuard(previous_mode))
}
}
}
}
impl Drop for ErrorModeGuard {
fn drop(&mut self) {
unsafe {
SetThreadErrorMode(self.0, ptr::null_mut());
}
}
}
fn with_get_last_error<T, F>(
wrap: fn(crate::error::WindowsError) -> crate::Error,
closure: F,
) -> Result<T, Option<crate::Error>>
where
F: FnOnce() -> Option<T>,
{
closure().ok_or_else(|| {
let error = unsafe { GetLastError() };
if error == 0 {
None
} else {
Some(wrap(crate::error::WindowsError(error as i32)))
}
})
}
#[allow(clippy::upper_case_acronyms)]
type BOOL = i32;
#[allow(clippy::upper_case_acronyms)]
type DWORD = u32;
#[allow(clippy::upper_case_acronyms)]
type HANDLE = isize;
#[allow(clippy::upper_case_acronyms)]
type HMODULE = isize;
#[allow(clippy::upper_case_acronyms)]
type FARPROC = Option<unsafe extern "system" fn() -> isize>;
#[allow(non_camel_case_types)]
type LOAD_LIBRARY_FLAGS = DWORD;
const SEM_FAILCRITICALERRORS: DWORD = 1;
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = 0x00000010;
pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = 0x00000002;
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = 0x00000040;
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = 0x00000020;
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = 0x00000200;
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 0x00001000;
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = 0x00000100;
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = 0x00000800;
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = 0x00000400;
pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = 0x00000008;
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = 0x00000080;
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = 0x00002000;