use super::key::RegistryKey;
use super::types::{Access, Hive, Wow64View};
use crate::{Error, Result};
use windows::Win32::Foundation::ERROR_FILE_NOT_FOUND;
use windows::Win32::System::Registry::*;
use windows::core::HSTRING;
pub struct RegistryKeyBuilder {
hive: Option<Hive>,
path: Option<String>,
access: Access,
wow64: Option<Wow64View>,
}
impl RegistryKeyBuilder {
pub fn new() -> Self {
RegistryKeyBuilder {
hive: None,
path: None,
access: Access::Read,
wow64: None,
}
}
pub fn hive(mut self, hive: Hive) -> Self {
self.hive = Some(hive);
self
}
pub fn path(mut self, path: impl Into<String>) -> Self {
self.path = Some(path.into());
self
}
pub fn read(mut self) -> Self {
self.access = Access::Read;
self
}
pub fn write(mut self) -> Self {
self.access = Access::ReadWrite;
self
}
pub fn read_write(mut self) -> Self {
self.access = Access::ReadWrite;
self
}
pub fn wow64_32(mut self) -> Self {
self.wow64 = Some(Wow64View::Key32);
self
}
pub fn wow64_64(mut self) -> Self {
self.wow64 = Some(Wow64View::Key64);
self
}
pub fn open(self) -> Result<RegistryKey> {
let hive = self.hive.ok_or_else(|| {
Error::InvalidParameter(crate::error::InvalidParameterError::new(
"hive",
"Registry hive must be specified",
))
})?;
let path = self.path.ok_or_else(|| {
Error::InvalidParameter(crate::error::InvalidParameterError::new(
"path",
"Registry path must be specified",
))
})?;
let mut sam_flags = self.access.to_sam_flags();
if let Some(wow64) = self.wow64 {
sam_flags |= wow64.to_sam_flags();
}
let subkey_wide = HSTRING::from(&path);
let mut handle = HKEY::default();
unsafe {
let result = RegOpenKeyExW(
hive.as_hkey(),
&subkey_wide,
0,
REG_SAM_FLAGS(sam_flags),
&mut handle,
);
if result.is_err() {
if result == ERROR_FILE_NOT_FOUND {
return Err(Error::Registry(crate::error::RegistryError::KeyNotFound(
crate::error::RegistryKeyNotFoundError::new(path),
)));
}
return Err(Error::WindowsApi(
crate::error::WindowsApiError::with_context(result.into(), "RegOpenKeyExW"),
));
}
}
Ok(RegistryKey::from_handle_with_metadata(
handle,
true,
Some(hive),
Some(path),
))
}
}
impl Default for RegistryKeyBuilder {
fn default() -> Self {
Self::new()
}
}