diff options
Diffstat (limited to 'library/std/src/sys/windows/compat.rs')
-rw-r--r-- | library/std/src/sys/windows/compat.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs new file mode 100644 index 00000000000..d6d433f9d08 --- /dev/null +++ b/library/std/src/sys/windows/compat.rs @@ -0,0 +1,72 @@ +//! A "compatibility layer" for spanning XP and Windows 7 +//! +//! The standard library currently binds many functions that are not available +//! on Windows XP, but we would also like to support building executables that +//! run on XP. To do this we specify all non-XP APIs as having a fallback +//! implementation to do something reasonable. +//! +//! This dynamic runtime detection of whether a function is available is +//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a +//! static-per-function which caches the result of the first check. In this +//! manner we pay a semi-large one-time cost up front for detecting whether a +//! function is available but afterwards it's just a load and a jump. + +use crate::ffi::CString; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sys::c; + +pub fn lookup(module: &str, symbol: &str) -> Option<usize> { + let mut module: Vec<u16> = module.encode_utf16().collect(); + module.push(0); + let symbol = CString::new(symbol).unwrap(); + unsafe { + let handle = c::GetModuleHandleW(module.as_ptr()); + match c::GetProcAddress(handle, symbol.as_ptr()) as usize { + 0 => None, + n => Some(n), + } + } +} + +pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize { + let value = lookup(module, symbol).unwrap_or(fallback); + ptr.store(value, Ordering::SeqCst); + value +} + +macro_rules! compat_fn { + ($module:ident: $( + $(#[$meta:meta])* + pub fn $symbol:ident($($argname:ident: $argtype:ty),*) + -> $rettype:ty { + $($body:expr);* + } + )*) => ($( + #[allow(unused_variables)] + $(#[$meta])* + pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + use crate::sync::atomic::{AtomicUsize, Ordering}; + use crate::mem; + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; + + static PTR: AtomicUsize = AtomicUsize::new(0); + + fn load() -> usize { + crate::sys::compat::store_func(&PTR, + stringify!($module), + stringify!($symbol), + fallback as usize) + } + unsafe extern "system" fn fallback($($argname: $argtype),*) + -> $rettype { + $($body);* + } + + let addr = match PTR.load(Ordering::SeqCst) { + 0 => load(), + n => n, + }; + mem::transmute::<usize, F>(addr)($($argname),*) + } + )*) +} |