1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use std::ffi::{OsString, OsStr};
13 use std::os::windows::prelude::*;
14 use std::ops::RangeFrom;
16 use libc::{c_void, c_long};
19 type LPCWSTR = *const u16;
21 type LPDWORD = *mut DWORD;
22 type LPBYTE = *mut u8;
25 const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
26 const KEY_WOW64_32KEY: REGSAM = 0x0200;
27 const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE |
28 KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE;
29 const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL;
30 const READ_CONTROL: REGSAM = 0x00020000;
31 const KEY_QUERY_VALUE: REGSAM = 0x0001;
32 const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008;
33 const KEY_NOTIFY: REGSAM = 0x0010;
34 const SYNCHRONIZE: REGSAM = 0x00100000;
35 const REG_SZ: DWORD = 1;
36 const ERROR_SUCCESS: i32 = 0;
37 const ERROR_NO_MORE_ITEMS: DWORD = 259;
40 pub type HKEY = *mut __HKEY__;
41 pub type PHKEY = *mut HKEY;
42 pub type REGSAM = DWORD;
43 pub type LPWSTR = *mut u16;
44 pub type PFILETIME = *mut c_void;
46 #[link(name = "advapi32")]
48 fn RegOpenKeyExW(hKey: HKEY,
52 phkResult: PHKEY) -> LONG;
53 fn RegQueryValueExW(hKey: HKEY,
58 lpcbData: LPDWORD) -> LONG;
59 fn RegEnumKeyExW(hKey: HKEY,
66 lpftLastWriteTime: PFILETIME) -> LONG;
67 fn RegCloseKey(hKey: HKEY) -> LONG;
70 pub struct RegistryKey(Repr);
72 struct OwnedKey(HKEY);
80 idx: RangeFrom<DWORD>,
84 unsafe impl Sync for RegistryKey {}
85 unsafe impl Send for RegistryKey {}
87 pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
90 fn raw(&self) -> HKEY {
92 Repr::Const(val) => val,
93 Repr::Owned(ref val) => val.0,
97 pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
98 let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
99 let mut ret = ptr::null_mut();
101 RegOpenKeyExW(self.raw(), key.as_ptr(), 0,
102 KEY_READ | KEY_WOW64_32KEY, &mut ret)
104 if err == ERROR_SUCCESS {
105 Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
107 Err(io::Error::from_raw_os_error(err as i32))
111 pub fn iter(&self) -> Iter {
112 Iter { idx: 0.., key: self }
115 pub fn query_str(&self, name: &str) -> io::Result<OsString> {
116 let name: &OsStr = name.as_ref();
117 let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
121 let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
122 &mut kind, ptr::null_mut(), &mut len);
123 if err != ERROR_SUCCESS {
124 return Err(io::Error::from_raw_os_error(err as i32))
127 return Err(io::Error::new(io::ErrorKind::Other,
128 "registry key wasn't a string"))
131 // The length here is the length in bytes, but we're using wide
132 // characters so we need to be sure to halve it for the capacity
134 let mut v = Vec::with_capacity(len as usize / 2);
135 let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
136 ptr::null_mut(), v.as_mut_ptr() as *mut _,
138 if err != ERROR_SUCCESS {
139 return Err(io::Error::from_raw_os_error(err as i32))
141 v.set_len(len as usize / 2);
143 // Some registry keys may have a terminating nul character, but
144 // we're not interested in that, so chop it off if it's there.
145 if v[v.len() - 1] == 0 {
148 Ok(OsString::from_wide(&v))
153 impl Drop for OwnedKey {
155 unsafe { RegCloseKey(self.0); }
159 impl<'a> Iterator for Iter<'a> {
160 type Item = io::Result<OsString>;
162 fn next(&mut self) -> Option<io::Result<OsString>> {
163 self.idx.next().and_then(|i| unsafe {
164 let mut v = Vec::with_capacity(256);
165 let mut len = v.capacity() as DWORD;
166 let ret = RegEnumKeyExW(self.key.raw(), i, v.as_mut_ptr(), &mut len,
167 ptr::null_mut(), ptr::null_mut(), ptr::null_mut(),
169 if ret == ERROR_NO_MORE_ITEMS as LONG {
171 } else if ret != ERROR_SUCCESS {
172 Some(Err(io::Error::from_raw_os_error(ret as i32)))
174 v.set_len(len as usize);
175 Some(Ok(OsString::from_wide(&v)))