blob: cd42b7d05ee384d4ec7b9b918d2c5def938b9420 [file] [log] [blame]
// 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),*)
}
)*)
}