Skip to main content

windows_erg/registry/
builder.rs

1//! Registry key builder for advanced opening options.
2
3use super::key::RegistryKey;
4use super::types::{Access, Hive, Wow64View};
5use crate::{Error, Result};
6use windows::Win32::Foundation::ERROR_FILE_NOT_FOUND;
7use windows::Win32::System::Registry::*;
8use windows::core::HSTRING;
9
10/// Builder for opening registry keys with specific options.
11pub struct RegistryKeyBuilder {
12    hive: Option<Hive>,
13    path: Option<String>,
14    access: Access,
15    wow64: Option<Wow64View>,
16}
17
18impl RegistryKeyBuilder {
19    /// Create a new registry key builder.
20    pub fn new() -> Self {
21        RegistryKeyBuilder {
22            hive: None,
23            path: None,
24            access: Access::Read,
25            wow64: None,
26        }
27    }
28
29    /// Set the registry hive.
30    pub fn hive(mut self, hive: Hive) -> Self {
31        self.hive = Some(hive);
32        self
33    }
34
35    /// Set the registry key path.
36    pub fn path(mut self, path: impl Into<String>) -> Self {
37        self.path = Some(path.into());
38        self
39    }
40
41    /// Set read-only access (default).
42    pub fn read(mut self) -> Self {
43        self.access = Access::Read;
44        self
45    }
46
47    /// Set write access.
48    pub fn write(mut self) -> Self {
49        self.access = Access::ReadWrite;
50        self
51    }
52
53    /// Set read-write access.
54    pub fn read_write(mut self) -> Self {
55        self.access = Access::ReadWrite;
56        self
57    }
58
59    /// Access the 32-bit registry view on 64-bit Windows.
60    pub fn wow64_32(mut self) -> Self {
61        self.wow64 = Some(Wow64View::Key32);
62        self
63    }
64
65    /// Access the 64-bit registry view (default on 64-bit Windows).
66    pub fn wow64_64(mut self) -> Self {
67        self.wow64 = Some(Wow64View::Key64);
68        self
69    }
70
71    /// Open the registry key with the specified options.
72    pub fn open(self) -> Result<RegistryKey> {
73        let hive = self.hive.ok_or_else(|| {
74            Error::InvalidParameter(crate::error::InvalidParameterError::new(
75                "hive",
76                "Registry hive must be specified",
77            ))
78        })?;
79        let path = self.path.ok_or_else(|| {
80            Error::InvalidParameter(crate::error::InvalidParameterError::new(
81                "path",
82                "Registry path must be specified",
83            ))
84        })?;
85
86        let mut sam_flags = self.access.to_sam_flags();
87        if let Some(wow64) = self.wow64 {
88            sam_flags |= wow64.to_sam_flags();
89        }
90
91        let subkey_wide = HSTRING::from(&path);
92        let mut handle = HKEY::default();
93
94        unsafe {
95            let result = RegOpenKeyExW(
96                hive.as_hkey(),
97                &subkey_wide,
98                0,
99                REG_SAM_FLAGS(sam_flags),
100                &mut handle,
101            );
102
103            if result.is_err() {
104                if result == ERROR_FILE_NOT_FOUND {
105                    return Err(Error::Registry(crate::error::RegistryError::KeyNotFound(
106                        crate::error::RegistryKeyNotFoundError::new(path),
107                    )));
108                }
109                return Err(Error::WindowsApi(
110                    crate::error::WindowsApiError::with_context(result.into(), "RegOpenKeyExW"),
111                ));
112            }
113        }
114
115        Ok(RegistryKey::from_handle_with_metadata(
116            handle,
117            true,
118            Some(hive),
119            Some(path),
120        ))
121    }
122}
123
124impl Default for RegistryKeyBuilder {
125    fn default() -> Self {
126        Self::new()
127    }
128}