Files
wfassoc/wfassoc/src/extra/winreg.rs
yyc12345 a3456e9fdd feat(windows): implement registry manipulation for file associations
- Add comprehensive error types for registry operations
- Implement ProgIdKind enum with Display and FromStr traits
- Create ApplicationVisitor and ClassesVisitor structs
- Add ExtKey methods for linking, unlinking and querying ProgId
- Implement ProgIdKey creation and deletion in registry
- Add safe delete function to prevent accidental registry cleanup
- Introduce Display and FromStr implementations for ExtKey and ProgIdKey
- Organize registry access through scoped and viewed key opening
- Enable setting default "Open With" verbs for file extensions
- Support both user and system level registry modifications
2025-10-29 10:31:00 +08:00

145 lines
3.8 KiB
Rust

//! 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<P: AsRef<OsStr>>(
regkey: &RegKey,
path: P,
perms: REG_SAM_FLAGS,
) -> std::io::Result<Option<RegKey>> {
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<T: FromRegValue, N: AsRef<OsStr>>(
regkey: &RegKey,
name: N,
) -> std::io::Result<Option<T>> {
match regkey.get_value::<T, N>(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<P: AsRef<OsStr>>(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<String> for ExpandString {
fn from(s: String) -> Self {
Self::new(s)
}
}
impl From<ExpandString> 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