feat: add application subkey shell verb function
This commit is contained in:
@@ -20,14 +20,16 @@ pub enum Error {
|
|||||||
#[error("registry operation error: {0}")]
|
#[error("registry operation error: {0}")]
|
||||||
BadRegOp(#[from] std::io::Error),
|
BadRegOp(#[from] std::io::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
BadSoleSubKey(#[from] regext::OnlySubKeyError),
|
|
||||||
#[error("{0}")]
|
|
||||||
UnexpectedBlankKey(#[from] regext::BlankPathError),
|
UnexpectedBlankKey(#[from] regext::BlankPathError),
|
||||||
|
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
LoadIconRc(#[from] concept::LoadIconRcError),
|
LoadIconRc(#[from] concept::LoadIconRcError),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
LoadStrRc(#[from] concept::LoadStrRcError),
|
LoadStrRc(#[from] concept::LoadStrRcError),
|
||||||
|
#[error("{0}")]
|
||||||
|
ParseVerb(#[from] concept::ParseVerbError),
|
||||||
|
#[error("{0}")]
|
||||||
|
ParseCmdLine(#[from] concept::ParseCmdLineError),
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@@ -458,6 +460,9 @@ impl AppPathsKey {
|
|||||||
.ok_or(Error::InexistantKey)
|
.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 = "";
|
const NAMEOF_DEFAULT: &str = "";
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -592,6 +597,9 @@ impl ApplicationsKey {
|
|||||||
Ok(())
|
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> {
|
fn open_view_for_getter(&self, view: View) -> Result<RegKey, Error> {
|
||||||
self.open_view_for_read(view)?
|
self.open_view_for_read(view)?
|
||||||
.this_key
|
.this_key
|
||||||
@@ -606,13 +614,83 @@ impl ApplicationsKey {
|
|||||||
|
|
||||||
const NAMEOF_SHELL_VERB_PART1: &str = "shell";
|
const NAMEOF_SHELL_VERB_PART1: &str = "shell";
|
||||||
const NAMEOF_SHELL_VERB_PART3: &str = "command";
|
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> {
|
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> {
|
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";
|
const NAMEOF_DEFAULT_ICON_PART1: &str = "DefaultIcon";
|
||||||
@@ -771,6 +849,8 @@ impl ExtKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// YYC MARK:
|
// 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"
|
// We do not support "Content Type" and "PerceivedType"
|
||||||
// because current interface are enough to use,
|
// because current interface are enough to use,
|
||||||
// and these types has not been made as concept struct in Rust.
|
// and these types has not been made as concept struct in Rust.
|
||||||
@@ -916,6 +996,8 @@ impl ProgIdKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// YYC MARK:
|
// 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
|
// Currently we only support (Default), FriendlyTypeName and DefaultIcon
|
||||||
// to just cover the basic usage.
|
// 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.
|
/// 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.
|
/// 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();
|
let mut subkey_enumerator = regkey.enum_keys();
|
||||||
|
|
||||||
// Get first one.
|
// Get first one.
|
||||||
let rv = match subkey_enumerator.next() {
|
let rv = match subkey_enumerator.next() {
|
||||||
Some(key) => key?,
|
Some(key) => key?,
|
||||||
None => return Err(OnlySubKeyError::NoSubKey),
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check whether there is second one.
|
// Check whether there is second one.
|
||||||
match subkey_enumerator.next() {
|
match subkey_enumerator.next() {
|
||||||
Some(_) => Err(OnlySubKeyError::TooManySubKey),
|
Some(_) => Ok(None),
|
||||||
None => Ok(rv),
|
None => Ok(Some(rv)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user