feat: add application subkey shell verb function
This commit is contained in:
@@ -20,14 +20,16 @@ pub enum Error {
|
||||
#[error("registry operation error: {0}")]
|
||||
BadRegOp(#[from] std::io::Error),
|
||||
#[error("{0}")]
|
||||
BadSoleSubKey(#[from] regext::OnlySubKeyError),
|
||||
#[error("{0}")]
|
||||
UnexpectedBlankKey(#[from] regext::BlankPathError),
|
||||
|
||||
#[error("{0}")]
|
||||
LoadIconRc(#[from] concept::LoadIconRcError),
|
||||
#[error("{0}")]
|
||||
LoadStrRc(#[from] concept::LoadStrRcError),
|
||||
#[error("{0}")]
|
||||
ParseVerb(#[from] concept::ParseVerbError),
|
||||
#[error("{0}")]
|
||||
ParseCmdLine(#[from] concept::ParseCmdLineError),
|
||||
}
|
||||
|
||||
// endregion
|
||||
@@ -458,6 +460,9 @@ impl AppPathsKey {
|
||||
.ok_or(Error::InexistantKey)
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/app-registration#using-the-app-paths-subkey
|
||||
|
||||
const NAMEOF_DEFAULT: &str = "";
|
||||
|
||||
///
|
||||
@@ -592,6 +597,9 @@ impl ApplicationsKey {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/app-registration#using-the-applications-subkey
|
||||
|
||||
fn open_view_for_getter(&self, view: View) -> Result<RegKey, Error> {
|
||||
self.open_view_for_read(view)?
|
||||
.this_key
|
||||
@@ -606,13 +614,83 @@ impl ApplicationsKey {
|
||||
|
||||
const NAMEOF_SHELL_VERB_PART1: &str = "shell";
|
||||
const NAMEOF_SHELL_VERB_PART3: &str = "command";
|
||||
const NAMEOF_SHELL_VERB_PART4: &str = "";
|
||||
|
||||
pub fn get_shell_verb(&self, view: View) -> Result<Option<ShellVerb>, Error> {
|
||||
todo!()
|
||||
let key = self.open_view_for_getter(view)?;
|
||||
|
||||
// Get shell subkey
|
||||
let shell_key = match regext::try_open_subkey_with_flags(
|
||||
&key,
|
||||
Self::NAMEOF_SHELL_VERB_PART1,
|
||||
KEY_READ,
|
||||
)? {
|
||||
Some(key) => key,
|
||||
None => return Ok(None),
|
||||
};
|
||||
// Get verb subkey name, then get subkey itself.
|
||||
let verb_key_name = match regext::get_sole_subkey_name(&shell_key)? {
|
||||
Some(key) => key,
|
||||
None => return Ok(None),
|
||||
};
|
||||
let verb_key =
|
||||
match regext::try_open_subkey_with_flags(&shell_key, &verb_key_name, KEY_READ)? {
|
||||
Some(key) => key,
|
||||
None => return Ok(None),
|
||||
};
|
||||
// Get command subkey.
|
||||
let command_key = match regext::try_open_subkey_with_flags(
|
||||
&verb_key,
|
||||
Self::NAMEOF_SHELL_VERB_PART3,
|
||||
KEY_READ,
|
||||
)? {
|
||||
Some(key) => key,
|
||||
None => return Ok(None),
|
||||
};
|
||||
// Get the default value of command subkey
|
||||
let command_default_value = match regext::try_get_value::<String, _>(
|
||||
&command_key,
|
||||
Self::NAMEOF_SHELL_VERB_PART4,
|
||||
)? {
|
||||
Some(value) => value,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
// Okey, return value.
|
||||
Ok(Some(ShellVerb::new(
|
||||
verb_key_name.parse()?,
|
||||
command_default_value.parse()?,
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn set_shell_verb(&mut self, scope: Scope, sv: Option<&ShellVerb>) -> Result<(), Error> {
|
||||
todo!()
|
||||
let key = self.open_scope_for_setter(scope)?;
|
||||
|
||||
match sv {
|
||||
Some(sv) => {
|
||||
// Create shell subkey
|
||||
let (shell_key, _) = key.create_subkey_with_flags(
|
||||
Self::NAMEOF_SHELL_VERB_PART1,
|
||||
KEY_READ | KEY_WRITE,
|
||||
)?;
|
||||
// Create verb key
|
||||
let (verb_key, _) = shell_key
|
||||
.create_subkey_with_flags(sv.get_verb().inner(), KEY_READ | KEY_WRITE)?;
|
||||
// Create command key
|
||||
let (command_key, _) = verb_key.create_subkey_with_flags(
|
||||
Self::NAMEOF_SHELL_VERB_PART3,
|
||||
KEY_READ | KEY_WRITE,
|
||||
)?;
|
||||
// Set command key default value
|
||||
command_key.set_value(Self::NAMEOF_SHELL_VERB_PART4, &sv.get_command().full())?;
|
||||
}
|
||||
None => {
|
||||
// Delete shell and its all subkey.
|
||||
key.delete_subkey_all(regext::blank_path_guard(Self::NAMEOF_SHELL_VERB_PART1)?)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const NAMEOF_DEFAULT_ICON_PART1: &str = "DefaultIcon";
|
||||
@@ -771,6 +849,8 @@ impl ExtKey {
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/fa-file-types#setting-optional-subkeys-and-file-type-extension-attributes
|
||||
//
|
||||
// We do not support "Content Type" and "PerceivedType"
|
||||
// because current interface are enough to use,
|
||||
// and these types has not been made as concept struct in Rust.
|
||||
@@ -916,6 +996,8 @@ impl ProgIdKey {
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/fa-progids#programmatic-identifier-elements-used-by-file-associations
|
||||
//
|
||||
// Currently we only support (Default), FriendlyTypeName and DefaultIcon
|
||||
// to just cover the basic usage.
|
||||
|
||||
|
||||
@@ -61,34 +61,26 @@ pub fn try_get_value<T: FromRegValue, N: AsRef<OsStr>>(
|
||||
}
|
||||
}
|
||||
|
||||
/// The error occurs when fetching the name of only subkey.
|
||||
#[derive(Debug, TeError)]
|
||||
pub enum OnlySubKeyError {
|
||||
#[error("registry operation error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("there is no any subkey in given RegKey")]
|
||||
NoSubKey,
|
||||
#[error("there is more than one subkey in given RegKey")]
|
||||
TooManySubKey,
|
||||
}
|
||||
|
||||
/// Get the name of only subkey in given key.
|
||||
///
|
||||
/// If there is only one subkey in given key, the return value is its name.
|
||||
/// If there is no any subkey, or has multiple subkeys, return None instead.
|
||||
/// If error occurs when fetching data, return Err(_).
|
||||
///
|
||||
/// This is usually used for ShellVerb fetching.
|
||||
pub fn get_sole_subkey_name(regkey: &RegKey) -> Result<String, OnlySubKeyError> {
|
||||
pub fn get_sole_subkey_name(regkey: &RegKey) -> std::io::Result<Option<String>> {
|
||||
let mut subkey_enumerator = regkey.enum_keys();
|
||||
|
||||
// Get first one.
|
||||
let rv = match subkey_enumerator.next() {
|
||||
Some(key) => key?,
|
||||
None => return Err(OnlySubKeyError::NoSubKey),
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
// Check whether there is second one.
|
||||
match subkey_enumerator.next() {
|
||||
Some(_) => Err(OnlySubKeyError::TooManySubKey),
|
||||
None => Ok(rv),
|
||||
Some(_) => Ok(None),
|
||||
None => Ok(Some(rv)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user