1
0

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

178
Cargo.lock generated
View File

@ -61,6 +61,12 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "bitflags"
version = "2.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
[[package]]
name = "bumpalo"
version = "3.19.0"
@ -119,6 +125,59 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "comfy-table"
version = "7.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b"
dependencies = [
"crossterm",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags",
"crossterm_winapi",
"document-features",
"parking_lot",
"rustix",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "document-features"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
dependencies = [
"litrs",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "heck"
version = "0.5.0"
@ -141,6 +200,33 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litrs"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.28"
@ -165,6 +251,29 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "proc-macro2"
version = "1.0.101"
@ -183,6 +292,15 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.11.3"
@ -212,12 +330,37 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
[[package]]
name = "rustix"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.60.2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "strsim"
version = "0.11.1"
@ -261,6 +404,18 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "utf8parse"
version = "0.2.2"
@ -360,10 +515,33 @@ name = "wfassoc_exec"
version = "0.1.0"
dependencies = [
"clap",
"comfy-table",
"thiserror",
"wfassoc",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-link"
version = "0.2.0"

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

View File

@ -10,3 +10,4 @@ license = "SPDX:MIT"
thiserror = { workspace = true }
wfassoc = { path="../wfassoc" }
clap = { version="4.5.48", features=["derive"]}
comfy-table = "7.2.1"

View File

@ -1,7 +1,8 @@
use clap::{Parser, Subcommand};
use comfy_table::Table;
use std::process;
use wfassoc::{Error as WfError};
use thiserror::Error as TeError;
use wfassoc::{Error as WfError, FileExt, Scope};
// region: Basic Types
@ -10,7 +11,7 @@ use thiserror::Error as TeError;
enum Error {
/// Error from wfassoc core.
#[error("{0}")]
Core(#[from] WfError)
Core(#[from] WfError),
}
/// Result type used in this executable.
@ -89,9 +90,40 @@ fn run_unregister(cli: Cli) -> Result<()> {
}
fn run_query(cli: Cli) -> Result<()> {
let exts = [
".jpg", ".jfif", ".gif", ".bmp", ".png", ".ico", ".jpeg", ".tif", ".tiff", ".webp", ".svg",
".kra", ".xcf", ".avif", ".qoi", ".apng", ".exr",
];
let mut table = Table::new();
table.set_header(["Extension", "Default Open", "Open With"]);
for ext in exts.iter().map(|e| FileExt::new(e).unwrap()) {
if let Some(ext_assoc) = ext.query(Scope::User) {
if ext_assoc.len_open_with_progid() == 0 {
table.add_row([ext.to_string().as_str(), ext_assoc.get_default(), ""]);
} else {
for (i, open_with_entry) in ext_assoc.iter_open_with_progids().enumerate() {
if i == 0 {
table.add_row([
ext.to_string().as_str(),
ext_assoc.get_default(),
open_with_entry,
]);
} else {
table.add_row(["", "", open_with_entry]);
}
}
}
} else {
table.add_row([ext.to_string().as_str(), "", ""]);
}
}
println!("{table}");
// let program = Program::new();
// program.query()?;
println!("Has privilege: {}", wfassoc::has_privilege());
//println!("Has privilege: {}", wfassoc::has_privilege());
Ok(())
}