//! This module expand `winreg` crate to make it more suit for this crate. use std::ffi::OsStr; use std::ops::Deref; use std::ops::DerefMut; use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND; use windows_sys::Win32::System::Registry::REG_SAM_FLAGS; use winreg::RegKey; use winreg::types::FromRegValue; // region: Extra Operations /// Get the subkey with given name. /// /// If error occurs when fetching given subkey, it return `Err(...)`, /// otherwise, it will return `Ok(Some(...))` if aubkey is existing, /// or `Ok(None)` if there is no suchsub key. /// /// Comparing with the function provided by winreg, /// it differ "no such subkey" error and other access error. pub fn try_open_subkey_with_flags>( regkey: &RegKey, path: P, perms: REG_SAM_FLAGS, ) -> std::io::Result> { match regkey.open_subkey_with_flags(path, perms) { Ok(v) => Ok(Some(v)), Err(e) => match e.raw_os_error() { Some(errno) => match errno as u32 { ERROR_FILE_NOT_FOUND => Ok(None), _ => Err(e) } _ => Err(e), }, } } /// Get the value by given key. /// /// If error occurs when fetching given key, it return `Err(...)`, /// otherwise, it will return `Ok(Some(...))` if key is existing, /// or `Ok(None)` if there is no such key. /// /// Comparing with the function provided by winreg, /// it differ "no such key" error and other access error. pub fn try_get_value>( regkey: &RegKey, name: N, ) -> std::io::Result> { match regkey.get_value::(name) { Ok(v) => Ok(Some(v)), Err(e) => match e.raw_os_error() { Some(errno) => match errno as u32 { ERROR_FILE_NOT_FOUND => Ok(None), _ => Err(e) } _ => Err(e), }, } } /// Passing empty string to `delete_subkey_all` may cause /// that the whole parent tree are deleted, not the subkey. /// So we create this "safe" function to prevent this horrible scenarios. pub fn safe_delete_subkey_all>(regkey: &RegKey, path: P) -> std::io::Result<()> { if path.as_ref().is_empty() { Err(std::io::Error::other("dangerous Registry delete_subkey_all")) } else { regkey.delete_subkey_all(path) } } // endregion // region: Expand String /// The struct basically is the alias of String, but make a slight difference with it, /// to make they are different when use it with String as generic argument. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ExpandString(String); impl ExpandString { /// Construct new ExpandString. pub fn new(s: String) -> Self { Self(s) } /// Create from &str pub fn from_str(s: &str) -> Self { Self(s.to_string()) } /// Get reference to internal String. pub fn as_str(&self) -> &str { &self.0 } /// Get mutable reference to internal String. pub fn as_mut_str(&mut self) -> &mut String { &mut self.0 } /// Comsule self, return internal String. pub fn into_inner(self) -> String { self.0 } } // Implement Deref trait to make it can be used like &str impl Deref for ExpandString { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } // Implement DerefMut trait impl DerefMut for ExpandString { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } // Implement From/Into trait for explicit convertion impl From for ExpandString { fn from(s: String) -> Self { Self::new(s) } } impl From for String { fn from(expand: ExpandString) -> Self { expand.into_inner() } } impl From<&str> for ExpandString { fn from(s: &str) -> Self { Self::from_str(s) } } // endregion