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.
11 use std::ffi::{OsString, OsStr};
13 use std::ops::RangeFrom;
15 use std::os::windows::prelude::*;
17 pub struct RegistryKey(Repr);
21 type LPDWORD = *mut DWORD;
22 type LPCWSTR = *const u16;
23 type LPWSTR = *mut u16;
24 type LONG = raw::c_long;
25 type PHKEY = *mut HKEY;
26 type PFILETIME = *mut u8;
27 type LPBYTE = *mut u8;
30 const ERROR_SUCCESS: DWORD = 0;
31 const ERROR_NO_MORE_ITEMS: DWORD = 259;
32 const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
33 const REG_SZ: DWORD = 1;
34 const KEY_READ: DWORD = 0x20019;
35 const KEY_WOW64_32KEY: DWORD = 0x200;
37 #[link(name = "advapi32")]
39 fn RegOpenKeyExW(key: HKEY,
45 fn RegEnumKeyExW(key: HKEY,
52 lpftLastWriteTime: PFILETIME)
54 fn RegQueryValueExW(hKey: HKEY,
61 fn RegCloseKey(hKey: HKEY) -> LONG;
64 struct OwnedKey(HKEY);
72 idx: RangeFrom<DWORD>,
76 unsafe impl Sync for Repr {}
77 unsafe impl Send for Repr {}
79 pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
82 fn raw(&self) -> HKEY {
84 Repr::Const(val) => val,
85 Repr::Owned(ref val) => val.0,
89 pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
90 let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
91 let mut ret = 0 as *mut _;
93 RegOpenKeyExW(self.raw(),
96 KEY_READ | KEY_WOW64_32KEY,
99 if err == ERROR_SUCCESS as LONG {
100 Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
102 Err(io::Error::from_raw_os_error(err as i32))
106 pub fn iter(&self) -> Iter {
113 pub fn query_str(&self, name: &str) -> io::Result<OsString> {
114 let name: &OsStr = name.as_ref();
115 let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
119 let err = RegQueryValueExW(self.raw(),
125 if err != ERROR_SUCCESS as LONG {
126 return Err(io::Error::from_raw_os_error(err as i32));
129 return Err(io::Error::new(io::ErrorKind::Other, "registry key wasn't a string"));
132 // The length here is the length in bytes, but we're using wide
133 // characters so we need to be sure to halve it for the capacity
135 let mut v = Vec::with_capacity(len as usize / 2);
136 let err = RegQueryValueExW(self.raw(),
140 v.as_mut_ptr() as *mut _,
142 if err != ERROR_SUCCESS as LONG {
143 return Err(io::Error::from_raw_os_error(err as i32));
145 v.set_len(len as usize / 2);
147 // Some registry keys may have a terminating nul character, but
148 // we're not interested in that, so chop it off if it's there.
149 if v[v.len() - 1] == 0 {
152 Ok(OsString::from_wide(&v))
157 impl Drop for OwnedKey {
165 impl<'a> Iterator for Iter<'a> {
166 type Item = io::Result<OsString>;
168 fn next(&mut self) -> Option<io::Result<OsString>> {
169 self.idx.next().and_then(|i| unsafe {
170 let mut v = Vec::with_capacity(256);
171 let mut len = v.capacity() as DWORD;
172 let ret = RegEnumKeyExW(self.key.raw(),
180 if ret == ERROR_NO_MORE_ITEMS as LONG {
182 } else if ret != ERROR_SUCCESS as LONG {
183 Some(Err(io::Error::from_raw_os_error(ret as i32)))
185 v.set_len(len as usize);
186 Some(Ok(OsString::from_wide(&v)))