1
0

refactor(winreg): reorganize Windows registry utilities into extra module

Move winreg_extra functionality into new extra/winreg module and restructure project layout
Add Windows icon handling utilities in extra/windows module
Update dependencies and clean up unused wincmd module
This commit is contained in:
2025-10-20 13:38:41 +08:00
parent d493285900
commit 26d867d42f
8 changed files with 119 additions and 25 deletions

7
Cargo.lock generated
View File

@ -739,6 +739,7 @@ dependencies = [
"regex",
"thiserror",
"uuid",
"widestring",
"windows-sys 0.60.2",
"winreg",
]
@ -764,6 +765,12 @@ dependencies = [
"wfassoc",
]
[[package]]
name = "widestring"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
[[package]]
name = "winapi"
version = "0.3.9"

View File

@ -12,9 +12,11 @@ windows-sys = { version = "0.60.2", features = [
"Win32_Security",
"Win32_System_SystemServices",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
"Win32_System_Registry",
] }
winreg = { version = "0.55.0", features = ["transactions"] }
widestring = "1.2.1"
indexmap = "2.11.4"
regex = "1.11.3"
uuid = "1.18.1"

7
wfassoc/src/extra.rs Normal file
View File

@ -0,0 +1,7 @@
//! The extension for some existing crates.
//! Some imported crates are not enough for my project,
//! so I need create something to enrich them.
pub mod winreg;
pub mod windows;

View File

@ -0,0 +1,96 @@
//! This module expand Windows-related stuff by `windows-sys` crate.
//! These features are not implemented in any crates (as I known scope)
//! and should be manually implemented for our file association use.
use std::path::Path;
use thiserror::Error as TeError;
use widestring::WideCString;
use windows_sys::Win32::UI::Shell::ExtractIconExW;
use windows_sys::Win32::UI::WindowsAndMessaging::{DestroyIcon, HICON};
// region: Icon
/// Error occurs when loading icon.
#[derive(Debug, TeError)]
#[error("error occurs when loading icon")]
pub enum LoadIconError {
EmbeddedNul(#[from] widestring::error::ContainsNul<widestring::WideChar>),
Other,
}
/// The size kind of loaded icon
#[derive(Debug, Clone, Copy)]
pub enum IconSizeKind {
/// Small Icon
Small,
/// Large Icon
Large,
}
/// The struct representing a loaded icon resource.
pub struct Icon {
icon: HICON,
}
impl Icon {
pub fn new(file: &Path, index: i32, kind: IconSizeKind) -> Result<Self, LoadIconError> {
let mut icon = HICON::default();
let icon_ptr = &mut icon as *mut HICON;
let file = WideCString::from_os_str(file.as_os_str())?;
let rv = unsafe {
match kind {
IconSizeKind::Small => {
ExtractIconExW(file.as_ptr(), index, Default::default(), icon_ptr, 1)
}
IconSizeKind::Large => {
ExtractIconExW(file.as_ptr(), index, icon_ptr, Default::default(), 1)
}
}
};
if rv != 1 || icon.is_null() {
Err(LoadIconError::Other)
} else {
Ok(Self { icon })
}
}
pub fn from_raw(hicon: HICON) -> Self {
Self { icon: hicon }
}
pub fn into_raw(self) -> HICON {
self.icon
}
}
impl Icon {
pub fn get_icon(&self) -> HICON {
self.icon
}
}
impl Drop for Icon {
fn drop(&mut self) {
if !self.icon.is_null() {
unsafe {
DestroyIcon(self.icon);
}
}
}
}
// endregion
// region: Cmd Path
pub struct CmdPath {}
// endregion
// region: Cmd Arguments
pub struct CmdArgs {}
// endregion

View File

@ -4,10 +4,9 @@
#[cfg(not(target_os = "windows"))]
compile_error!("Crate wfassoc is only supported on Windows.");
pub mod assoc;
pub mod extra;
pub mod utilities;
pub mod wincmd;
pub mod winreg_extra;
pub mod assoc;
use assoc::{Ext, ProgId};
use indexmap::{IndexMap, IndexSet};
@ -411,10 +410,10 @@ impl Program {
// Open key for this extension.
// If there is no such key, return directly.
if let Some(subkey) =
winreg_extra::try_open_subkey_with_flags(&classes, ext.to_string(), KEY_WRITE)?
extra::winreg::try_open_subkey_with_flags(&classes, ext.to_string(), KEY_WRITE)?
{
// Only delete the default key if it is equal to our ProgId
if let Some(value) = winreg_extra::try_get_value::<String, _>(&subkey, "")? {
if let Some(value) = extra::winreg::try_get_value::<String, _>(&subkey, "")? {
if value == prog_id.to_string() {
// Delete the default key.
subkey.delete_value("")?;
@ -449,10 +448,10 @@ impl Program {
// Open key for this extension if possible
let rv =
match winreg_extra::try_open_subkey_with_flags(&classes, ext.to_string(), KEY_READ)? {
match extra::winreg::try_open_subkey_with_flags(&classes, ext.to_string(), KEY_READ)? {
Some(subkey) => {
// Try get associated ProgId if possible
match winreg_extra::try_get_value::<String, _>(&subkey, "")? {
match extra::winreg::try_get_value::<String, _>(&subkey, "")? {
Some(value) => Some(ProgId::from(value.as_str())),
None => None,
}

View File

@ -1,18 +0,0 @@
//! This module involve Windows command line stuff, like argument splittor and path,
//! because they are different with POSIX standard.
// region: Cmd Path
pub struct CmdPath {
}
// endregion
// region: Cmd Arguments
pub struct CmdArgs {
}
// endregion

View File

@ -117,6 +117,7 @@ fn run_unregister(cli: &Cli, target: &Target) -> Result<()> {
fn run_query(cli: &Cli) -> Result<()> {
let composition = Composition::new(cli)?;
// Show file association
let mut table = Table::new();
table.set_header(["Extension", "Hybrid", "User", "System"]);