#[cfg(all(libloading_docs, not(windows)))]
mod windows_imports {
pub(super) enum WORD {}
pub(super) struct DWORD;
pub(super) enum HMODULE {}
pub(super) enum FARPROC {}
pub(super) mod consts {
use super::DWORD;
pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD;
pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD;
pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD;
}
}
#[cfg(any(not(libloading_docs), windows))]
mod windows_imports {
extern crate winapi;
pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC};
pub(super) use self::winapi::shared::ntdef::WCHAR;
pub(super) use self::winapi::um::{errhandlingapi, libloaderapi};
pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt};
pub(super) const SEM_FAILCE: DWORD = 1;
pub(super) mod consts {
pub(crate) use super::winapi::um::libloaderapi::{
LOAD_IGNORE_CODE_AUTHZ_LEVEL,
LOAD_LIBRARY_AS_DATAFILE,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE,
LOAD_LIBRARY_AS_IMAGE_RESOURCE,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR,
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,
LOAD_LIBRARY_SEARCH_SYSTEM32,
LOAD_LIBRARY_SEARCH_USER_DIRS,
LOAD_WITH_ALTERED_SEARCH_PATH,
LOAD_LIBRARY_REQUIRE_SIGNED_TARGET,
LOAD_LIBRARY_SAFE_CURRENT_DIRS,
};
}
}
use self::windows_imports::*;
use util::{ensure_compatible_types, cstr_cow_from_bytes};
use std::ffi::{OsStr, OsString};
use std::{fmt, io, marker, mem, ptr};
pub struct Library(HMODULE);
unsafe impl Send for Library {}
unsafe impl Sync for Library {}
impl Library {
#[inline]
pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
Library::load_with_flags(filename, 0)
}
pub fn this() -> Result<Library, crate::Error> {
unsafe {
let mut handle: HMODULE = std::ptr::null_mut();
with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
let result = libloaderapi::GetModuleHandleExW(0, std::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<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
let ret = unsafe {
let mut handle: HMODULE = std::ptr::null_mut();
with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
let result = libloaderapi::GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle);
if result == 0 {
None
} else {
Some(Library(handle))
}
}).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
};
drop(wide_filename); ret
}
pub unsafe fn load_with_flags<P: AsRef<OsStr>>(filename: P, flags: DWORD) -> Result<Library, crate::Error> {
let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
let _guard = ErrorModeGuard::new();
let ret = with_get_last_error(|source| crate::Error::LoadLibraryExW { source }, || {
let handle =
libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags);
if handle.is_null() {
None
} else {
Some(Library(handle))
}
}).map_err(|e| e.unwrap_or(crate::Error::LoadLibraryExWUnknown));
drop(wide_filename); ret
}
pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
ensure_compatible_types::<T, FARPROC>()?;
let symbol = cstr_cow_from_bytes(symbol)?;
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
let symbol = libloaderapi::GetProcAddress(self.0, symbol.as_ptr());
if symbol.is_null() {
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: WORD) -> 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 *mut _;
let symbol = libloaderapi::GetProcAddress(self.0, ordinal);
if symbol.is_null() {
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 { libloaderapi::FreeLibrary(self.0) == 0 } {
None
} else {
Some(())
}
}).map_err(|e| e.unwrap_or(crate::Error::FreeLibraryUnknown));
std::mem::forget(self);
result
}
}
impl Drop for Library {
fn drop(&mut self) {
unsafe { libloaderapi::FreeLibrary(self.0); }
}
}
impl fmt::Debug for Library {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
let mut buf =
mem::MaybeUninit::<[mem::MaybeUninit::<WCHAR>; 1024]>::uninit().assume_init();
let len = libloaderapi::GetModuleFileNameW(self.0,
buf[..].as_mut_ptr().cast(), 1024) as usize;
if len == 0 {
f.write_str(&format!("Library@{:p}", self.0))
} else {
let string: OsString = OsString::from_wide(
&*(&buf[..len] as *const [_] as *const [WCHAR])
);
f.write_str(&format!("Library@{:p} from {:?}", self.0, string))
}
}
}
}
pub struct Symbol<T> {
pointer: FARPROC,
pd: marker::PhantomData<T>
}
impl<T> Symbol<T> {
pub fn into_raw(self) -> FARPROC {
self.pointer
}
}
impl<T> Symbol<Option<T>> {
pub fn lift_option(self) -> Option<Symbol<T>> {
if self.pointer.is_null() {
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> ::std::ops::Deref for Symbol<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe {
&*(&self.pointer as *const *mut _ as *const T)
}
}
}
impl<T> fmt::Debug for Symbol<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&format!("Symbol@{:p}", self.pointer))
}
}
struct ErrorModeGuard(DWORD);
impl ErrorModeGuard {
#[allow(clippy::if_same_then_else)]
fn new() -> Option<ErrorModeGuard> {
unsafe {
let mut previous_mode = 0;
if errhandlingapi::SetThreadErrorMode(SEM_FAILCE, &mut previous_mode) == 0 {
None
} else if previous_mode == SEM_FAILCE {
None
} else {
Some(ErrorModeGuard(previous_mode))
}
}
}
}
impl Drop for ErrorModeGuard {
fn drop(&mut self) {
unsafe {
errhandlingapi::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 { errhandlingapi::GetLastError() };
if error == 0 {
None
} else {
Some(wrap(crate::error::WindowsError(io::Error::from_raw_os_error(error as i32))))
}
})
}
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL;
pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE;
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE;
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE;
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32;
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS;
pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH;
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS;