]>
Commit | Line | Data |
---|---|---|
c1a9b12d SL |
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::io; | |
12 | use std::ffi::{OsString, OsStr}; | |
13 | use std::os::windows::prelude::*; | |
e9174d1e | 14 | use std::ptr; |
92a42be0 SL |
15 | use libc::{c_void, c_long}; |
16 | ||
17 | type DWORD = u32; | |
18 | type LPCWSTR = *const u16; | |
19 | type LONG = c_long; | |
20 | type LPDWORD = *mut DWORD; | |
21 | type LPBYTE = *mut u8; | |
22 | ||
c1a9b12d SL |
23 | |
24 | const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; | |
25 | const KEY_WOW64_32KEY: REGSAM = 0x0200; | |
26 | const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE | | |
27 | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE; | |
28 | const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL; | |
29 | const READ_CONTROL: REGSAM = 0x00020000; | |
30 | const KEY_QUERY_VALUE: REGSAM = 0x0001; | |
31 | const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008; | |
32 | const KEY_NOTIFY: REGSAM = 0x0010; | |
33 | const SYNCHRONIZE: REGSAM = 0x00100000; | |
34 | const REG_SZ: DWORD = 1; | |
92a42be0 | 35 | const ERROR_SUCCESS: i32 = 0; |
c1a9b12d SL |
36 | |
37 | enum __HKEY__ {} | |
38 | pub type HKEY = *mut __HKEY__; | |
39 | pub type PHKEY = *mut HKEY; | |
40 | pub type REGSAM = DWORD; | |
41 | pub type LPWSTR = *mut u16; | |
42 | pub type PFILETIME = *mut c_void; | |
43 | ||
44 | #[link(name = "advapi32")] | |
45 | extern "system" { | |
46 | fn RegOpenKeyExW(hKey: HKEY, | |
47 | lpSubKey: LPCWSTR, | |
48 | ulOptions: DWORD, | |
49 | samDesired: REGSAM, | |
50 | phkResult: PHKEY) -> LONG; | |
51 | fn RegQueryValueExW(hKey: HKEY, | |
52 | lpValueName: LPCWSTR, | |
53 | lpReserved: LPDWORD, | |
54 | lpType: LPDWORD, | |
55 | lpData: LPBYTE, | |
56 | lpcbData: LPDWORD) -> LONG; | |
c1a9b12d SL |
57 | fn RegCloseKey(hKey: HKEY) -> LONG; |
58 | } | |
59 | ||
60 | pub struct RegistryKey(Repr); | |
61 | ||
62 | struct OwnedKey(HKEY); | |
63 | ||
64 | enum Repr { | |
65 | Const(HKEY), | |
66 | Owned(OwnedKey), | |
67 | } | |
68 | ||
c1a9b12d SL |
69 | unsafe impl Sync for RegistryKey {} |
70 | unsafe impl Send for RegistryKey {} | |
71 | ||
72 | pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); | |
73 | ||
74 | impl RegistryKey { | |
75 | fn raw(&self) -> HKEY { | |
76 | match self.0 { | |
77 | Repr::Const(val) => val, | |
78 | Repr::Owned(ref val) => val.0, | |
79 | } | |
80 | } | |
81 | ||
82 | pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> { | |
83 | let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>(); | |
e9174d1e | 84 | let mut ret = ptr::null_mut(); |
c1a9b12d SL |
85 | let err = unsafe { |
86 | RegOpenKeyExW(self.raw(), key.as_ptr(), 0, | |
87 | KEY_READ | KEY_WOW64_32KEY, &mut ret) | |
88 | }; | |
89 | if err == ERROR_SUCCESS { | |
90 | Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) | |
91 | } else { | |
92 | Err(io::Error::from_raw_os_error(err as i32)) | |
93 | } | |
94 | } | |
95 | ||
c1a9b12d SL |
96 | pub fn query_str(&self, name: &str) -> io::Result<OsString> { |
97 | let name: &OsStr = name.as_ref(); | |
98 | let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>(); | |
99 | let mut len = 0; | |
100 | let mut kind = 0; | |
101 | unsafe { | |
e9174d1e SL |
102 | let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(), |
103 | &mut kind, ptr::null_mut(), &mut len); | |
c1a9b12d SL |
104 | if err != ERROR_SUCCESS { |
105 | return Err(io::Error::from_raw_os_error(err as i32)) | |
106 | } | |
107 | if kind != REG_SZ { | |
108 | return Err(io::Error::new(io::ErrorKind::Other, | |
109 | "registry key wasn't a string")) | |
110 | } | |
111 | ||
112 | // The length here is the length in bytes, but we're using wide | |
113 | // characters so we need to be sure to halve it for the capacity | |
114 | // passed in. | |
115 | let mut v = Vec::with_capacity(len as usize / 2); | |
e9174d1e SL |
116 | let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(), |
117 | ptr::null_mut(), v.as_mut_ptr() as *mut _, | |
c1a9b12d SL |
118 | &mut len); |
119 | if err != ERROR_SUCCESS { | |
120 | return Err(io::Error::from_raw_os_error(err as i32)) | |
121 | } | |
122 | v.set_len(len as usize / 2); | |
123 | ||
124 | // Some registry keys may have a terminating nul character, but | |
125 | // we're not interested in that, so chop it off if it's there. | |
126 | if v[v.len() - 1] == 0 { | |
127 | v.pop(); | |
128 | } | |
129 | Ok(OsString::from_wide(&v)) | |
130 | } | |
131 | } | |
132 | } | |
133 | ||
134 | impl Drop for OwnedKey { | |
135 | fn drop(&mut self) { | |
136 | unsafe { RegCloseKey(self.0); } | |
137 | } | |
138 | } |