// 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 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::ffi::{OsStr, OsString}; 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, 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 { let key = key.encode_wide().chain(Some(0)).collect::>(); 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 { let name: &OsStr = name.as_ref(); let name = name.encode_wide().chain(Some(0)).collect::>(); 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; fn next(&mut self) -> Option> { 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))) } }) } }