Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| // Copyright 2014 The Rust Project Developers. See the COPYRIGHT | |
| // file at the top-level directory of this distribution and at | |
| // http://rust-lang.org/COPYRIGHT. | |
| // | |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
| // option. This file may not be copied, modified, or distributed | |
| // except according to those terms. | |
| //! 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 ffi::CString; | |
| use sync::atomic::{AtomicUsize, Ordering}; | |
| use 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: $( | |
| pub fn $symbol:ident($($argname:ident: $argtype:ty),*) | |
| -> $rettype:ty { | |
| $($body:expr);* | |
| } | |
| )*) => ($( | |
| #[allow(unused_variables)] | |
| pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { | |
| use sync::atomic::{AtomicUsize, Ordering}; | |
| use mem; | |
| type F = unsafe extern "system" fn($($argtype),*) -> $rettype; | |
| static PTR: AtomicUsize = AtomicUsize::new(0); | |
| fn load() -> usize { | |
| ::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),*) | |
| } | |
| )*) | |
| } |