1use super::*;
2
3#[repr(transparent)]
5#[derive(Debug)]
6pub struct Key(pub(crate) HKEY);
7
8impl Key {
9 pub fn create<T: AsRef<str>>(&self, path: T) -> Result<Self> {
11 self.options().read().write().create().open(path)
12 }
13
14 pub fn open<T: AsRef<str>>(&self, path: T) -> Result<Self> {
16 self.options().read().open(path)
17 }
18
19 pub fn options(&self) -> OpenOptions<'_> {
21 OpenOptions::new(self)
22 }
23
24 pub unsafe fn from_raw(handle: *mut core::ffi::c_void) -> Self {
31 Self(handle)
32 }
33
34 pub fn as_raw(&self) -> *mut core::ffi::c_void {
36 self.0
37 }
38
39 pub fn rename<F: AsRef<str>, T: AsRef<str>>(&self, from: F, to: T) -> Result<()> {
41 let result = unsafe { RegRenameKey(self.0, pcwstr(from).as_ptr(), pcwstr(to).as_ptr()) };
42 win32_error(result)
43 }
44
45 pub fn remove_tree<T: AsRef<str>>(&self, path: T) -> Result<()> {
47 let result = unsafe { RegDeleteTreeW(self.0, pcwstr(path).as_ptr()) };
48 win32_error(result)
49 }
50
51 pub fn remove_value<T: AsRef<str>>(&self, name: T) -> Result<()> {
53 let result = unsafe { RegDeleteValueW(self.0, pcwstr(name).as_ptr()) };
54 win32_error(result)
55 }
56
57 pub fn keys(&self) -> Result<KeyIterator<'_>> {
59 KeyIterator::new(self)
60 }
61
62 pub fn values(&self) -> Result<ValueIterator<'_>> {
64 ValueIterator::new(self)
65 }
66
67 pub fn set_u32<T: AsRef<str>>(&self, name: T, value: u32) -> Result<()> {
69 self.set_bytes(name, Type::U32, &value.to_le_bytes())
70 }
71
72 pub fn set_u64<T: AsRef<str>>(&self, name: T, value: u64) -> Result<()> {
74 self.set_bytes(name, Type::U64, &value.to_le_bytes())
75 }
76
77 pub fn set_string<T: AsRef<str>, U: AsRef<str>>(&self, name: T, value: U) -> Result<()> {
79 self.set_bytes(name, Type::String, pcwstr(value).as_bytes())
80 }
81
82 pub fn set_hstring<T: AsRef<str>>(
84 &self,
85 name: T,
86 value: &windows_strings::HSTRING,
87 ) -> Result<()> {
88 self.set_bytes(name, Type::String, as_bytes(value))
89 }
90
91 pub fn set_expand_string<T: AsRef<str>, U: AsRef<str>>(&self, name: T, value: U) -> Result<()> {
93 self.set_bytes(name, Type::ExpandString, pcwstr(value).as_bytes())
94 }
95
96 pub fn set_expand_hstring<T: AsRef<str>>(
98 &self,
99 name: T,
100 value: &windows_strings::HSTRING,
101 ) -> Result<()> {
102 self.set_bytes(name, Type::ExpandString, as_bytes(value))
103 }
104
105 pub fn set_multi_string<T: AsRef<str>>(&self, name: T, value: &[T]) -> Result<()> {
107 let value = multi_pcwstr(value);
108 self.set_bytes(name, Type::MultiString, value.as_bytes())
109 }
110
111 pub fn set_value<T: AsRef<str>>(&self, name: T, value: &Value) -> Result<()> {
113 self.set_bytes(name, value.ty(), value)
114 }
115
116 pub fn set_bytes<T: AsRef<str>>(&self, name: T, ty: Type, value: &[u8]) -> Result<()> {
118 unsafe { self.raw_set_bytes(pcwstr(name).as_raw(), ty, value) }
119 }
120
121 pub fn get_type<T: AsRef<str>>(&self, name: T) -> Result<Type> {
123 let (ty, _) = unsafe { self.raw_get_info(pcwstr(name).as_raw())? };
124 Ok(ty)
125 }
126
127 pub fn get_value<T: AsRef<str>>(&self, name: T) -> Result<Value> {
129 let name = pcwstr(name);
130 let (ty, len) = unsafe { self.raw_get_info(name.as_raw())? };
131 let mut data = Data::new(len);
132 unsafe { self.raw_get_bytes(name.as_raw(), &mut data)? };
133 Ok(Value { data, ty })
134 }
135
136 pub fn get_u32<T: AsRef<str>>(&self, name: T) -> Result<u32> {
138 Ok(self.get_u64(name)?.try_into()?)
139 }
140
141 pub fn get_u64<T: AsRef<str>>(&self, name: T) -> Result<u64> {
143 let value = &mut [0; 8];
144 let (ty, value) = unsafe { self.raw_get_bytes(pcwstr(name).as_raw(), value)? };
145 from_le_bytes(ty, value)
146 }
147
148 pub fn get_string<T: AsRef<str>>(&self, name: T) -> Result<String> {
150 self.get_value(name)?.try_into()
151 }
152
153 pub fn get_hstring<T: AsRef<str>>(&self, name: T) -> Result<HSTRING> {
155 let name = pcwstr(name);
156 let (ty, len) = unsafe { self.raw_get_info(name.as_raw())? };
157
158 if !matches!(ty, Type::String | Type::ExpandString) {
159 return Err(invalid_data());
160 }
161
162 let mut value = HStringBuilder::new(len / 2);
163 unsafe { self.raw_get_bytes(name.as_raw(), value.as_bytes_mut())? };
164 value.trim_end();
165 Ok(value.into())
166 }
167
168 pub fn get_multi_string<T: AsRef<str>>(&self, name: T) -> Result<Vec<String>> {
170 self.get_value(name)?.try_into()
171 }
172
173 #[track_caller]
181 pub unsafe fn raw_set_bytes<N: AsRef<PCWSTR>>(
182 &self,
183 name: N,
184 ty: Type,
185 value: &[u8],
186 ) -> Result<()> {
187 if cfg!(debug_assertions) {
188 if matches!(ty, Type::String | Type::ExpandString | Type::MultiString) {
190 debug_assert!(
191 value.get(value.len() - 2) == Some(&0),
192 "`value` isn't null-terminated"
193 );
194 debug_assert!(value.last() == Some(&0), "`value` isn't null-terminated");
195 }
196 }
197
198 let result = unsafe {
199 RegSetValueExW(
200 self.0,
201 name.as_ref().as_ptr(),
202 0,
203 ty.into(),
204 value.as_ptr(),
205 value.len().try_into()?,
206 )
207 };
208
209 win32_error(result)
210 }
211
212 pub unsafe fn raw_get_info<N: AsRef<PCWSTR>>(&self, name: N) -> Result<(Type, usize)> {
220 let mut ty = 0;
221 let mut len = 0;
222
223 let result = unsafe {
224 RegQueryValueExW(
225 self.0,
226 name.as_ref().as_ptr(),
227 null(),
228 &mut ty,
229 core::ptr::null_mut(),
230 &mut len,
231 )
232 };
233
234 win32_error(result)?;
235 Ok((ty.into(), len as usize))
236 }
237
238 pub unsafe fn raw_get_bytes<'a, N: AsRef<PCWSTR>>(
246 &self,
247 name: N,
248 value: &'a mut [u8],
249 ) -> Result<(Type, &'a [u8])> {
250 let mut ty = 0;
251 let mut len = value.len().try_into()?;
252
253 let result = unsafe {
254 RegQueryValueExW(
255 self.0,
256 name.as_ref().as_ptr(),
257 null(),
258 &mut ty,
259 value.as_mut_ptr(),
260 &mut len,
261 )
262 };
263
264 win32_error(result)?;
265 Ok((ty.into(), value.get(0..len as usize).unwrap()))
266 }
267}
268
269impl Drop for Key {
270 fn drop(&mut self) {
271 unsafe { RegCloseKey(self.0) };
272 }
273}