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. 4 // 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. 10 11 use std::ffi::{OsStr, OsString}; 12 use std::io; 13 use std::ops::RangeFrom; 14 use std::os::raw; 15 use std::os::windows::prelude::*; 16 17 pub struct RegistryKey(Repr); 18 19 type HKEY = *mut u8; 20 type DWORD = u32; 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; 28 type REGSAM = u32; 29 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; 36 37 #[link(name = "advapi32")] 38 extern "system" { RegOpenKeyExW( key: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY, ) -> LONG39 fn RegOpenKeyExW( 40 key: HKEY, 41 lpSubKey: LPCWSTR, 42 ulOptions: DWORD, 43 samDesired: REGSAM, 44 phkResult: PHKEY, 45 ) -> LONG; RegEnumKeyExW( key: HKEY, dwIndex: DWORD, lpName: LPWSTR, lpcName: LPDWORD, lpReserved: LPDWORD, lpClass: LPWSTR, lpcClass: LPDWORD, lpftLastWriteTime: PFILETIME, ) -> LONG46 fn RegEnumKeyExW( 47 key: HKEY, 48 dwIndex: DWORD, 49 lpName: LPWSTR, 50 lpcName: LPDWORD, 51 lpReserved: LPDWORD, 52 lpClass: LPWSTR, 53 lpcClass: LPDWORD, 54 lpftLastWriteTime: PFILETIME, 55 ) -> LONG; RegQueryValueExW( hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD, ) -> LONG56 fn RegQueryValueExW( 57 hKey: HKEY, 58 lpValueName: LPCWSTR, 59 lpReserved: LPDWORD, 60 lpType: LPDWORD, 61 lpData: LPBYTE, 62 lpcbData: LPDWORD, 63 ) -> LONG; RegCloseKey(hKey: HKEY) -> LONG64 fn RegCloseKey(hKey: HKEY) -> LONG; 65 } 66 67 struct OwnedKey(HKEY); 68 69 enum Repr { 70 Const(HKEY), 71 Owned(OwnedKey), 72 } 73 74 pub struct Iter<'a> { 75 idx: RangeFrom<DWORD>, 76 key: &'a RegistryKey, 77 } 78 79 unsafe impl Sync for Repr {} 80 unsafe impl Send for Repr {} 81 82 pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); 83 84 impl RegistryKey { raw(&self) -> HKEY85 fn raw(&self) -> HKEY { 86 match self.0 { 87 Repr::Const(val) => val, 88 Repr::Owned(ref val) => val.0, 89 } 90 } 91 open(&self, key: &OsStr) -> io::Result<RegistryKey>92 pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> { 93 let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>(); 94 let mut ret = 0 as *mut _; 95 let err = unsafe { 96 RegOpenKeyExW( 97 self.raw(), 98 key.as_ptr(), 99 0, 100 KEY_READ | KEY_WOW64_32KEY, 101 &mut ret, 102 ) 103 }; 104 if err == ERROR_SUCCESS as LONG { 105 Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) 106 } else { 107 Err(io::Error::from_raw_os_error(err as i32)) 108 } 109 } 110 iter(&self) -> Iter111 pub fn iter(&self) -> Iter { 112 Iter { 113 idx: 0.., 114 key: self, 115 } 116 } 117 query_str(&self, name: &str) -> io::Result<OsString>118 pub fn query_str(&self, name: &str) -> io::Result<OsString> { 119 let name: &OsStr = name.as_ref(); 120 let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>(); 121 let mut len = 0; 122 let mut kind = 0; 123 unsafe { 124 let err = RegQueryValueExW( 125 self.raw(), 126 name.as_ptr(), 127 0 as *mut _, 128 &mut kind, 129 0 as *mut _, 130 &mut len, 131 ); 132 if err != ERROR_SUCCESS as LONG { 133 return Err(io::Error::from_raw_os_error(err as i32)); 134 } 135 if kind != REG_SZ { 136 return Err(io::Error::new( 137 io::ErrorKind::Other, 138 "registry key wasn't a string", 139 )); 140 } 141 142 // The length here is the length in bytes, but we're using wide 143 // characters so we need to be sure to halve it for the capacity 144 // passed in. 145 let mut v = Vec::with_capacity(len as usize / 2); 146 let err = RegQueryValueExW( 147 self.raw(), 148 name.as_ptr(), 149 0 as *mut _, 150 0 as *mut _, 151 v.as_mut_ptr() as *mut _, 152 &mut len, 153 ); 154 if err != ERROR_SUCCESS as LONG { 155 return Err(io::Error::from_raw_os_error(err as i32)); 156 } 157 v.set_len(len as usize / 2); 158 159 // Some registry keys may have a terminating nul character, but 160 // we're not interested in that, so chop it off if it's there. 161 if v[v.len() - 1] == 0 { 162 v.pop(); 163 } 164 Ok(OsString::from_wide(&v)) 165 } 166 } 167 } 168 169 impl Drop for OwnedKey { drop(&mut self)170 fn drop(&mut self) { 171 unsafe { 172 RegCloseKey(self.0); 173 } 174 } 175 } 176 177 impl<'a> Iterator for Iter<'a> { 178 type Item = io::Result<OsString>; 179 next(&mut self) -> Option<io::Result<OsString>>180 fn next(&mut self) -> Option<io::Result<OsString>> { 181 self.idx.next().and_then(|i| unsafe { 182 let mut v = Vec::with_capacity(256); 183 let mut len = v.capacity() as DWORD; 184 let ret = RegEnumKeyExW( 185 self.key.raw(), 186 i, 187 v.as_mut_ptr(), 188 &mut len, 189 0 as *mut _, 190 0 as *mut _, 191 0 as *mut _, 192 0 as *mut _, 193 ); 194 if ret == ERROR_NO_MORE_ITEMS as LONG { 195 None 196 } else if ret != ERROR_SUCCESS as LONG { 197 Some(Err(io::Error::from_raw_os_error(ret as i32))) 198 } else { 199 v.set_len(len as usize); 200 Some(Ok(OsString::from_wide(&v))) 201 } 202 }) 203 } 204 } 205