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
;
15 use libc
::{DWORD, LPCWSTR, LONG, LPDWORD, LPBYTE, ERROR_SUCCESS}
;
18 const HKEY_LOCAL_MACHINE
: HKEY
= 0x80000002 as HKEY
;
19 const KEY_WOW64_32KEY
: REGSAM
= 0x0200;
20 const KEY_READ
: REGSAM
= (STANDARD_RIGTS_READ
| KEY_QUERY_VALUE
|
21 KEY_ENUMERATE_SUB_KEYS
| KEY_NOTIFY
) & !SYNCHRONIZE
;
22 const STANDARD_RIGTS_READ
: REGSAM
= READ_CONTROL
;
23 const READ_CONTROL
: REGSAM
= 0x00020000;
24 const KEY_QUERY_VALUE
: REGSAM
= 0x0001;
25 const KEY_ENUMERATE_SUB_KEYS
: REGSAM
= 0x0008;
26 const KEY_NOTIFY
: REGSAM
= 0x0010;
27 const SYNCHRONIZE
: REGSAM
= 0x00100000;
28 const REG_SZ
: DWORD
= 1;
29 const ERROR_NO_MORE_ITEMS
: DWORD
= 259;
32 pub type HKEY
= *mut __HKEY__
;
33 pub type PHKEY
= *mut HKEY
;
34 pub type REGSAM
= DWORD
;
35 pub type LPWSTR
= *mut u16;
36 pub type PFILETIME
= *mut c_void
;
38 #[link(name = "advapi32")]
40 fn RegOpenKeyExW(hKey
: HKEY
,
44 phkResult
: PHKEY
) -> LONG
;
45 fn RegQueryValueExW(hKey
: HKEY
,
50 lpcbData
: LPDWORD
) -> LONG
;
51 fn RegEnumKeyExW(hKey
: HKEY
,
58 lpftLastWriteTime
: PFILETIME
) -> LONG
;
59 fn RegCloseKey(hKey
: HKEY
) -> LONG
;
62 pub struct RegistryKey(Repr
);
64 struct OwnedKey(HKEY
);
72 idx
: RangeFrom
<DWORD
>,
76 unsafe impl Sync
for RegistryKey {}
77 unsafe impl Send
for RegistryKey {}
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(), key
.as_ptr(), 0,
94 KEY_READ
| KEY_WOW64_32KEY
, &mut ret
)
96 if err
== ERROR_SUCCESS
{
97 Ok(RegistryKey(Repr
::Owned(OwnedKey(ret
))))
99 Err(io
::Error
::from_raw_os_error(err
as i32))
103 pub fn iter(&self) -> Iter
{
104 Iter { idx: 0.., key: self }
107 pub fn query_str(&self, name
: &str) -> io
::Result
<OsString
> {
108 let name
: &OsStr
= name
.as_ref();
109 let name
= name
.encode_wide().chain(Some(0)).collect
::<Vec
<_
>>();
113 let err
= RegQueryValueExW(self.raw(), name
.as_ptr(), 0 as *mut _
,
114 &mut kind
, 0 as *mut _
, &mut len
);
115 if err
!= ERROR_SUCCESS
{
116 return Err(io
::Error
::from_raw_os_error(err
as i32))
119 return Err(io
::Error
::new(io
::ErrorKind
::Other
,
120 "registry key wasn't a string"))
123 // The length here is the length in bytes, but we're using wide
124 // characters so we need to be sure to halve it for the capacity
126 let mut v
= Vec
::with_capacity(len
as usize / 2);
127 let err
= RegQueryValueExW(self.raw(), name
.as_ptr(), 0 as *mut _
,
128 0 as *mut _
, v
.as_mut_ptr() as *mut _
,
130 if err
!= ERROR_SUCCESS
{
131 return Err(io
::Error
::from_raw_os_error(err
as i32))
133 v
.set_len(len
as usize / 2);
135 // Some registry keys may have a terminating nul character, but
136 // we're not interested in that, so chop it off if it's there.
137 if v
[v
.len() - 1] == 0 {
140 Ok(OsString
::from_wide(&v
))
145 impl Drop
for OwnedKey
{
147 unsafe { RegCloseKey(self.0); }
151 impl<'a
> Iterator
for Iter
<'a
> {
152 type Item
= io
::Result
<OsString
>;
154 fn next(&mut self) -> Option
<io
::Result
<OsString
>> {
155 self.idx
.next().and_then(|i
| unsafe {
156 let mut v
= Vec
::with_capacity(256);
157 let mut len
= v
.capacity() as DWORD
;
158 let ret
= RegEnumKeyExW(self.key
.raw(), i
, v
.as_mut_ptr(), &mut len
,
159 0 as *mut _
, 0 as *mut _
, 0 as *mut _
,
161 if ret
== ERROR_NO_MORE_ITEMS
as LONG
{
163 } else if ret
!= ERROR_SUCCESS
{
164 Some(Err(io
::Error
::from_raw_os_error(ret
as i32)))
166 v
.set_len(len
as usize);
167 Some(Ok(OsString
::from_wide(&v
)))