summaryrefslogtreecommitdiff
path: root/cc/src/registry.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cc/src/registry.rs')
-rw-r--r--cc/src/registry.rs190
1 files changed, 190 insertions, 0 deletions
diff --git a/cc/src/registry.rs b/cc/src/registry.rs
new file mode 100644
index 0000000..a452723
--- /dev/null
+++ b/cc/src/registry.rs
@@ -0,0 +1,190 @@
+// Copyright 2015 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.
+
+use std::ffi::{OsString, OsStr};
+use std::io;
+use std::ops::RangeFrom;
+use std::os::raw;
+use std::os::windows::prelude::*;
+
+pub struct RegistryKey(Repr);
+
+type HKEY = *mut u8;
+type DWORD = u32;
+type LPDWORD = *mut DWORD;
+type LPCWSTR = *const u16;
+type LPWSTR = *mut u16;
+type LONG = raw::c_long;
+type PHKEY = *mut HKEY;
+type PFILETIME = *mut u8;
+type LPBYTE = *mut u8;
+type REGSAM = u32;
+
+const ERROR_SUCCESS: DWORD = 0;
+const ERROR_NO_MORE_ITEMS: DWORD = 259;
+const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
+const REG_SZ: DWORD = 1;
+const KEY_READ: DWORD = 0x20019;
+const KEY_WOW64_32KEY: DWORD = 0x200;
+
+#[link(name = "advapi32")]
+extern "system" {
+ fn RegOpenKeyExW(key: HKEY,
+ lpSubKey: LPCWSTR,
+ ulOptions: DWORD,
+ samDesired: REGSAM,
+ phkResult: PHKEY)
+ -> LONG;
+ fn RegEnumKeyExW(key: HKEY,
+ dwIndex: DWORD,
+ lpName: LPWSTR,
+ lpcName: LPDWORD,
+ lpReserved: LPDWORD,
+ lpClass: LPWSTR,
+ lpcClass: LPDWORD,
+ lpftLastWriteTime: PFILETIME)
+ -> LONG;
+ fn RegQueryValueExW(hKey: HKEY,
+ lpValueName: LPCWSTR,
+ lpReserved: LPDWORD,
+ lpType: LPDWORD,
+ lpData: LPBYTE,
+ lpcbData: LPDWORD)
+ -> LONG;
+ fn RegCloseKey(hKey: HKEY) -> LONG;
+}
+
+struct OwnedKey(HKEY);
+
+enum Repr {
+ Const(HKEY),
+ Owned(OwnedKey),
+}
+
+pub struct Iter<'a> {
+ idx: RangeFrom<DWORD>,
+ key: &'a RegistryKey,
+}
+
+unsafe impl Sync for Repr {}
+unsafe impl Send for Repr {}
+
+pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
+
+impl RegistryKey {
+ fn raw(&self) -> HKEY {
+ match self.0 {
+ Repr::Const(val) => val,
+ Repr::Owned(ref val) => val.0,
+ }
+ }
+
+ pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
+ let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
+ let mut ret = 0 as *mut _;
+ let err = unsafe {
+ RegOpenKeyExW(self.raw(),
+ key.as_ptr(),
+ 0,
+ KEY_READ | KEY_WOW64_32KEY,
+ &mut ret)
+ };
+ if err == ERROR_SUCCESS as LONG {
+ Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
+ } else {
+ Err(io::Error::from_raw_os_error(err as i32))
+ }
+ }
+
+ pub fn iter(&self) -> Iter {
+ Iter {
+ idx: 0..,
+ key: self,
+ }
+ }
+
+ pub fn query_str(&self, name: &str) -> io::Result<OsString> {
+ let name: &OsStr = name.as_ref();
+ let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
+ let mut len = 0;
+ let mut kind = 0;
+ unsafe {
+ let err = RegQueryValueExW(self.raw(),
+ name.as_ptr(),
+ 0 as *mut _,
+ &mut kind,
+ 0 as *mut _,
+ &mut len);
+ if err != ERROR_SUCCESS as LONG {
+ return Err(io::Error::from_raw_os_error(err as i32));
+ }
+ if kind != REG_SZ {
+ return Err(io::Error::new(io::ErrorKind::Other, "registry key wasn't a string"));
+ }
+
+ // The length here is the length in bytes, but we're using wide
+ // characters so we need to be sure to halve it for the capacity
+ // passed in.
+ let mut v = Vec::with_capacity(len as usize / 2);
+ let err = RegQueryValueExW(self.raw(),
+ name.as_ptr(),
+ 0 as *mut _,
+ 0 as *mut _,
+ v.as_mut_ptr() as *mut _,
+ &mut len);
+ if err != ERROR_SUCCESS as LONG {
+ return Err(io::Error::from_raw_os_error(err as i32));
+ }
+ v.set_len(len as usize / 2);
+
+ // Some registry keys may have a terminating nul character, but
+ // we're not interested in that, so chop it off if it's there.
+ if v[v.len() - 1] == 0 {
+ v.pop();
+ }
+ Ok(OsString::from_wide(&v))
+ }
+ }
+}
+
+impl Drop for OwnedKey {
+ fn drop(&mut self) {
+ unsafe {
+ RegCloseKey(self.0);
+ }
+ }
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = io::Result<OsString>;
+
+ fn next(&mut self) -> Option<io::Result<OsString>> {
+ self.idx.next().and_then(|i| unsafe {
+ let mut v = Vec::with_capacity(256);
+ let mut len = v.capacity() as DWORD;
+ let ret = RegEnumKeyExW(self.key.raw(),
+ i,
+ v.as_mut_ptr(),
+ &mut len,
+ 0 as *mut _,
+ 0 as *mut _,
+ 0 as *mut _,
+ 0 as *mut _);
+ if ret == ERROR_NO_MORE_ITEMS as LONG {
+ None
+ } else if ret != ERROR_SUCCESS as LONG {
+ Some(Err(io::Error::from_raw_os_error(ret as i32)))
+ } else {
+ v.set_len(len as usize);
+ Some(Ok(OsString::from_wide(&v)))
+ }
+ })
+ }
+}