write shit

This commit is contained in:
2025-10-09 15:32:22 +08:00
parent 682be6ab58
commit 2c8cb26ebf
4 changed files with 279 additions and 19 deletions

View File

@@ -1,6 +1,9 @@
//! This crate provide utilities fetching and manilupating Windows file association.
//! All code under crate are following Microsoft document: https://learn.microsoft.com/en-us/windows/win32/shell/customizing-file-types-bumper
#[cfg(not(target_os = "windows"))]
compile_error!("Crate wfassoc is only supported on Windows.");
use regex::Regex;
use std::fmt::Display;
use std::path::PathBuf;
@@ -8,9 +11,6 @@ use std::str::FromStr;
use std::sync::LazyLock;
use thiserror::Error as TeError;
#[cfg(not(target_os = "windows"))]
compile_error!("Crate wfassoc is only supported on Windows.");
// region: Error Types
/// All possible error occurs in this crate.
@@ -29,6 +29,7 @@ pub enum Error {
// endregion
/// The scope where wfassoc will operate.
#[derive(Debug, Copy, Clone)]
pub enum Scope {
/// Scope for current user.
User,
@@ -40,17 +41,17 @@ pub enum Scope {
///
/// It usually means that checking whether current process is running as Administrator.
/// Return true if it is, otherwise false.
///
///
/// Reference: https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership
pub fn has_privilege() -> bool {
use windows_sys::core::BOOL;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Security::{
SECURITY_NT_AUTHORITY, PSID, AllocateAndInitializeSid, CheckTokenMembership, FreeSid
AllocateAndInitializeSid, CheckTokenMembership, FreeSid, PSID, SECURITY_NT_AUTHORITY,
};
use windows_sys::Win32::System::SystemServices:: {
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS
use windows_sys::Win32::System::SystemServices::{
DOMAIN_ALIAS_RID_ADMINS, SECURITY_BUILTIN_DOMAIN_RID,
};
use windows_sys::core::BOOL;
let nt_authority = SECURITY_NT_AUTHORITY.clone();
let mut administrators_group: PSID = PSID::default();
@@ -75,13 +76,8 @@ pub fn has_privilege() -> bool {
}
let mut is_member: BOOL = BOOL::default();
let success: BOOL = unsafe {
CheckTokenMembership(
HANDLE::default(),
administrators_group,
&mut is_member,
)
};
let success: BOOL =
unsafe { CheckTokenMembership(HANDLE::default(), administrators_group, &mut is_member) };
unsafe {
FreeSid(administrators_group);
@@ -90,7 +86,7 @@ pub fn has_privilege() -> bool {
if success == 0 {
panic!("Win32 CheckTokenMembership() failed");
}
is_member != 0
}
@@ -113,6 +109,10 @@ impl FileExt {
None => Err(ParseFileExtError::new()),
}
}
pub fn query(&self, scope: Scope) -> Option<FileExtAssoc> {
FileExtAssoc::new(self, scope)
}
}
/// The error occurs when try parsing string into FileExt.
@@ -140,6 +140,55 @@ impl FromStr for FileExt {
}
}
/// The association infomations of specific file extension.
pub struct FileExtAssoc {
default: String,
open_with_progids: Vec<String>,
}
impl FileExtAssoc {
fn new(file_ext: &FileExt, scope: Scope) -> Option<Self> {
let hk = match scope {
Scope::User => winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER),
Scope::System => winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE),
};
let classes = hk
.open_subkey_with_flags("Software\\Classes", winreg::enums::KEY_READ)
.unwrap();
let thisext =
match classes.open_subkey_with_flags(file_ext.to_string(), winreg::enums::KEY_READ) {
Ok(v) => v,
Err(e) => return None,
};
let default = thisext.get_value("").unwrap_or(String::new());
let open_with_progids = if let Ok(progids) =
thisext.open_subkey_with_flags("OpenWithProdIds", winreg::enums::KEY_READ)
{
progids.enum_keys().map(|x| x.unwrap()).collect()
} else {
Vec::new()
};
Some(Self {
default,
open_with_progids,
})
}
pub fn get_default(&self) -> &str {
&self.default
}
pub fn len_open_with_progid(&self) -> usize {
self.open_with_progids.len()
}
pub fn iter_open_with_progids(&self) -> impl Iterator<Item = &str> {
self.open_with_progids.iter().map(|s| s.as_str())
}
}
// endregion
// region: Executable Resource