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:
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -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"
|
||||
|
||||
@ -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
7
wfassoc/src/extra.rs
Normal 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;
|
||||
|
||||
96
wfassoc/src/extra/windows.rs
Normal file
96
wfassoc/src/extra/windows.rs
Normal 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
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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"]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user