Skip to main content

windows_registry/
key.rs

1use super::*;
2
3/// A registry key.
4#[repr(transparent)]
5#[derive(Debug)]
6pub struct Key(pub(crate) HKEY);
7
8impl Key {
9    /// Creates a registry key. If the key already exists, the function opens it.
10    pub fn create<T: AsRef<str>>(&self, path: T) -> Result<Self> {
11        self.options().read().write().create().open(path)
12    }
13
14    /// Opens a registry key.
15    pub fn open<T: AsRef<str>>(&self, path: T) -> Result<Self> {
16        self.options().read().open(path)
17    }
18
19    /// Creates an `OpenOptions` object for the registry key.
20    pub fn options(&self) -> OpenOptions<'_> {
21        OpenOptions::new(self)
22    }
23
24    /// Constructs a registry key from an existing handle.
25    ///
26    /// # Safety
27    ///
28    /// This function takes ownership of the handle.
29    /// The handle must be owned by the caller and safe to free with `RegCloseKey`.
30    pub unsafe fn from_raw(handle: *mut core::ffi::c_void) -> Self {
31        Self(handle)
32    }
33
34    /// Returns the underlying registry key handle.
35    pub fn as_raw(&self) -> *mut core::ffi::c_void {
36        self.0
37    }
38
39    /// Changes the name of the specified registry key.
40    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    /// Removes the registry keys and values of the specified key recursively.
46    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    /// Removes the registry value.
52    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    /// Creates an iterator of registry key names.
58    pub fn keys(&self) -> Result<KeyIterator<'_>> {
59        KeyIterator::new(self)
60    }
61
62    /// Creates an iterator of registry values.
63    pub fn values(&self) -> Result<ValueIterator<'_>> {
64        ValueIterator::new(self)
65    }
66
67    /// Sets the name and value in the registry key.
68    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    /// Sets the name and value in the registry key.
73    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    /// Sets the name and value in the registry key.
78    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    /// Sets the name and value in the registry key.
83    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    /// Sets the name and value in the registry key.
92    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    /// Sets the name and value in the registry key.
97    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    /// Sets the name and value in the registry key.
106    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    /// Sets the name and value in the registry key.
112    pub fn set_value<T: AsRef<str>>(&self, name: T, value: &Value) -> Result<()> {
113        self.set_bytes(name, value.ty(), value)
114    }
115
116    /// Sets the name and value in the registry key.
117    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    /// Gets the type for the name in the registry key.
122    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    /// Gets the value for the name in the registry key.
128    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    /// Gets the value for the name in the registry key.
137    pub fn get_u32<T: AsRef<str>>(&self, name: T) -> Result<u32> {
138        Ok(self.get_u64(name)?.try_into()?)
139    }
140
141    /// Gets the value for the name in the registry key.
142    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    /// Gets the value for the name in the registry key.
149    pub fn get_string<T: AsRef<str>>(&self, name: T) -> Result<String> {
150        self.get_value(name)?.try_into()
151    }
152
153    /// Gets the value for the name in the registry key.
154    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    /// Gets the value for the name in the registry key.
169    pub fn get_multi_string<T: AsRef<str>>(&self, name: T) -> Result<Vec<String>> {
170        self.get_value(name)?.try_into()
171    }
172
173    /// Sets the name and value in the registry key.
174    ///
175    /// This method avoids any allocations.
176    ///
177    /// # Safety
178    ///
179    /// The `PCWSTR` pointer needs to be valid for reads up until and including the next `\0`.
180    #[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            // RegSetValueExW expects string data to be null terminated.
189            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    /// Gets the type and length for the name in the registry key.
213    ///
214    /// This method avoids any allocations.
215    ///
216    /// # Safety
217    ///
218    /// The `PCWSTR` pointer needs to be valid for reads up until and including the next `\0`.
219    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    /// Gets the value for the name in the registry key.
239    ///
240    /// This method avoids any allocations.
241    ///
242    /// # Safety
243    ///
244    /// The `PCWSTR` pointer needs to be valid for reads up until and including the next `\0`.
245    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}