1 //! Dynamic library facilities.
3 //! A simple wrapper over the platform's dynamic library facilities
8 pub struct DynamicLibrary {
12 impl Drop for DynamicLibrary {
15 dl::close(self.handle)
21 /// Lazily open a dynamic library. When passed None it gives a
22 /// handle to the calling process
23 pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
24 let maybe_library = dl::open(filename.map(|path| path.as_os_str()));
26 // The dynamic library must not be constructed if there is
27 // an error opening the library so the destructor does not
31 Ok(handle) => Ok(DynamicLibrary { handle })
35 /// Accesses the value at the symbol of the dynamic library.
36 pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
37 // This function should have a lifetime constraint of 'a on
38 // T but that feature is still unimplemented
40 let raw_string = CString::new(symbol).unwrap();
41 let maybe_symbol_value = dl::symbol(self.handle, raw_string.as_ptr());
43 // The value must not be constructed if there is an error so
44 // the destructor does not run.
45 match maybe_symbol_value {
47 Ok(symbol_value) => Ok(symbol_value as *mut T)
57 use std::ffi::{CStr, OsStr, CString};
58 use std::os::unix::prelude::*;
62 pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
63 check_for_errors_in(|| {
66 Some(filename) => open_external(filename),
67 None => open_internal(),
73 unsafe fn open_external(filename: &OsStr) -> *mut u8 {
74 let s = CString::new(filename.as_bytes()).unwrap();
75 libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8
78 unsafe fn open_internal() -> *mut u8 {
79 libc::dlopen(ptr::null(), libc::RTLD_LAZY) as *mut u8
82 fn check_for_errors_in<T, F>(f: F) -> Result<T, String>
83 where F: FnOnce() -> T,
85 use std::sync::{Mutex, Once};
86 static INIT: Once = Once::new();
87 static mut LOCK: *mut Mutex<()> = ptr::null_mut();
90 LOCK = Box::into_raw(Box::new(Mutex::new(())));
92 // dlerror isn't thread safe, so we need to lock around this entire
94 let _guard = (*LOCK).lock();
95 let _old_error = libc::dlerror();
99 let last_error = libc::dlerror() as *const _;
100 let ret = if ptr::null() == last_error {
103 let s = CStr::from_ptr(last_error).to_bytes();
104 Err(str::from_utf8(s).unwrap().to_owned())
111 pub(super) unsafe fn symbol(
113 symbol: *const libc::c_char,
114 ) -> Result<*mut u8, String> {
115 check_for_errors_in(|| {
116 libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8
119 pub(super) unsafe fn close(handle: *mut u8) {
120 libc::dlclose(handle as *mut libc::c_void); ()
128 use std::os::windows::prelude::*;
131 use libc::{c_uint, c_void, c_char};
134 type HMODULE = *mut u8;
136 type LPCWSTR = *const u16;
137 type LPCSTR = *const i8;
140 fn SetThreadErrorMode(dwNewMode: DWORD,
141 lpOldMode: *mut DWORD) -> c_uint;
142 fn LoadLibraryW(name: LPCWSTR) -> HMODULE;
143 fn GetModuleHandleExW(dwFlags: DWORD,
145 handle: *mut HMODULE) -> BOOL;
146 fn GetProcAddress(handle: HMODULE,
147 name: LPCSTR) -> *mut c_void;
148 fn FreeLibrary(handle: HMODULE) -> BOOL;
151 pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
152 // disable "dll load failed" error dialog.
153 let prev_error_mode = unsafe {
154 // SEM_FAILCRITICALERRORS 0x01
155 let new_error_mode = 1;
156 let mut prev_error_mode = 0;
157 let result = SetThreadErrorMode(new_error_mode,
158 &mut prev_error_mode);
160 return Err(io::Error::last_os_error().to_string())
165 let result = match filename {
167 let filename_str: Vec<_> =
168 filename.encode_wide().chain(Some(0)).collect();
169 let result = unsafe {
170 LoadLibraryW(filename_str.as_ptr())
175 let mut handle = ptr::null_mut();
176 let succeeded = unsafe {
177 GetModuleHandleExW(0 as DWORD, ptr::null(), &mut handle)
180 Err(io::Error::last_os_error().to_string())
182 Ok(handle as *mut u8)
188 SetThreadErrorMode(prev_error_mode, ptr::null_mut());
194 pub(super) unsafe fn symbol(
196 symbol: *const c_char,
197 ) -> Result<*mut u8, String> {
198 let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
202 pub(super) unsafe fn close(handle: *mut u8) {
203 FreeLibrary(handle as HMODULE);
206 fn ptr_result<T>(ptr: *mut T) -> Result<*mut T, String> {
208 Err(io::Error::last_os_error().to_string())