1
0

feat: add more guard and const in lowlevel

This commit is contained in:
2026-05-18 15:43:16 +08:00
parent 91c7fdda70
commit bbcea1f4d2
4 changed files with 136 additions and 58 deletions

View File

@@ -105,9 +105,9 @@ bool WFProgramQueryExt(Token in_program, View in_view, size_t in_index, Token *o
bool WFExtStatusDestroy(Token in_ext_status);
bool WFExtStatuGetName(Token in_ext_status, CStyleString *out_name);
bool WFExtStatusGetName(Token in_ext_status, CStyleString *out_name);
bool WFExtStatuGetIcon(Token in_ext_status, HICON *out_icon);
bool WFExtStatusGetIcon(Token in_ext_status, HICON *out_icon);
#ifdef __cplusplus
} // extern "C"

View File

@@ -577,7 +577,7 @@ pub extern "C" fn WFExtStatusDestroy(in_ext_status: in_param_ty!(Token)) -> bool
}
#[unsafe(no_mangle)]
pub extern "C" fn WFExtStatuGetName(
pub extern "C" fn WFExtStatusGetName(
in_ext_status: in_param_ty!(Token),
out_name: out_param_ty!(CStyleString),
) -> bool {
@@ -591,7 +591,7 @@ pub extern "C" fn WFExtStatuGetName(
}
#[unsafe(no_mangle)]
pub extern "C" fn WFExtStatuGetIcon(
pub extern "C" fn WFExtStatusGetIcon(
in_ext_status: in_param_ty!(Token),
out_icon: out_param_ty!(HICON),
) -> bool {

View File

@@ -30,6 +30,8 @@ pub enum Error {
ParseVerb(#[from] concept::ParseVerbError),
#[error("{0}")]
ParseCmdLine(#[from] concept::ParseCmdLineError),
#[error("{0}")]
ParseExt(#[from] concept::ParseExtError),
}
// endregion
@@ -303,6 +305,9 @@ impl From<View> for OpenKeyTerritory {
}
}
const PERM_R: u32 = KEY_READ;
const PERM_RW: u32 = KEY_READ | KEY_WRITE;
/// The purpose of opening this key.
#[derive(Debug, Copy, Clone)]
enum OpenKeyPurpose {
@@ -312,6 +317,15 @@ enum OpenKeyPurpose {
ReadWrite,
}
impl OpenKeyPurpose {
fn to_permission(&self) -> u32 {
match self {
OpenKeyPurpose::Read => PERM_R,
OpenKeyPurpose::ReadWrite => PERM_RW,
}
}
}
/// Check whether we have enough privilege when operating in given territory and purpose.
/// If we have, simply return, otherwise return error.
fn check_privilege(territory: OpenKeyTerritory, purpose: OpenKeyPurpose) -> Result<(), Error> {
@@ -382,10 +396,7 @@ impl AppPathsKey {
// check privilege
check_privilege(territory, purpose)?;
// Fetch the permission
let perms = match purpose {
OpenKeyPurpose::Read => KEY_READ,
OpenKeyPurpose::ReadWrite => KEY_READ | KEY_WRITE,
};
let perms = purpose.to_permission();
// get the root key
let hk = match territory {
@@ -395,7 +406,8 @@ impl AppPathsKey {
OpenKeyTerritory::Hybrid => panic!("unexpected hybrid key territory"),
};
// navigate to App Paths
let app_paths = hk.open_subkey_with_flags(Self::APP_PATHS, perms)?;
let app_paths =
hk.open_subkey_with_flags(regext::blank_path_guard(Self::APP_PATHS)?, perms)?;
// open file name key if possible
let this_app = regext::try_open_subkey_with_flags(
&app_paths,
@@ -429,7 +441,7 @@ impl AppPathsKey {
if let None = key.this_key {
let _ = key.parent_key.create_subkey_with_flags(
regext::blank_path_guard(self.key_name.inner())?,
KEY_READ | KEY_WRITE,
PERM_RW,
)?;
Ok(true)
} else {
@@ -535,10 +547,7 @@ impl ApplicationsKey {
// check privilege
check_privilege(territory, purpose)?;
// Fetch the permission
let perms = match purpose {
OpenKeyPurpose::Read => KEY_READ,
OpenKeyPurpose::ReadWrite => KEY_READ | KEY_WRITE,
};
let perms = purpose.to_permission();
// get the root key
let hk = match territory {
@@ -547,12 +556,14 @@ impl ApplicationsKey {
OpenKeyTerritory::Hybrid => RegKey::predef(HKEY_CLASSES_ROOT),
};
let applications = match territory {
OpenKeyTerritory::User | OpenKeyTerritory::System => {
hk.open_subkey_with_flags(Self::FULL_APPLICATIONS, perms)?
}
OpenKeyTerritory::Hybrid => {
hk.open_subkey_with_flags(Self::PARTIAL_APPLICATIONS, perms)?
}
OpenKeyTerritory::User | OpenKeyTerritory::System => hk.open_subkey_with_flags(
regext::blank_path_guard(Self::FULL_APPLICATIONS)?,
perms,
)?,
OpenKeyTerritory::Hybrid => hk.open_subkey_with_flags(
regext::blank_path_guard(Self::PARTIAL_APPLICATIONS)?,
perms,
)?,
};
// open app key if possible
let this_app = regext::try_open_subkey_with_flags(
@@ -582,7 +593,7 @@ impl ApplicationsKey {
if let None = key.this_key {
let _ = key.parent_key.create_subkey_with_flags(
regext::blank_path_guard(self.key_name.inner())?,
KEY_READ | KEY_WRITE,
PERM_RW,
)?;
Ok(true)
} else {
@@ -622,8 +633,8 @@ impl ApplicationsKey {
// Get shell subkey
let shell_key = match regext::try_open_subkey_with_flags(
&key,
Self::NAMEOF_SHELL_VERB_PART1,
KEY_READ,
regext::blank_path_guard(Self::NAMEOF_SHELL_VERB_PART1)?,
PERM_R,
)? {
Some(key) => key,
None => return Ok(None),
@@ -633,16 +644,19 @@ impl ApplicationsKey {
Some(key) => key,
None => return Ok(None),
};
let verb_key =
match regext::try_open_subkey_with_flags(&shell_key, &verb_key_name, KEY_READ)? {
let verb_key = match regext::try_open_subkey_with_flags(
&shell_key,
regext::blank_path_guard(&verb_key_name)?,
PERM_R,
)? {
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,
regext::blank_path_guard(Self::NAMEOF_SHELL_VERB_PART3)?,
PERM_R,
)? {
Some(key) => key,
None => return Ok(None),
@@ -670,16 +684,16 @@ impl ApplicationsKey {
Some(sv) => {
// Create shell subkey
let (shell_key, _) = key.create_subkey_with_flags(
Self::NAMEOF_SHELL_VERB_PART1,
KEY_READ | KEY_WRITE,
regext::blank_path_guard(Self::NAMEOF_SHELL_VERB_PART1)?,
PERM_RW,
)?;
// Create verb key
let (verb_key, _) = shell_key
.create_subkey_with_flags(sv.get_verb().inner(), KEY_READ | KEY_WRITE)?;
let (verb_key, _) =
shell_key.create_subkey_with_flags(sv.get_verb().inner(), PERM_RW)?;
// Create command key
let (command_key, _) = verb_key.create_subkey_with_flags(
Self::NAMEOF_SHELL_VERB_PART3,
KEY_READ | KEY_WRITE,
regext::blank_path_guard(Self::NAMEOF_SHELL_VERB_PART3)?,
PERM_RW,
)?;
// Set command key default value
command_key.set_value(Self::NAMEOF_SHELL_VERB_PART4, &sv.get_command().full())?;
@@ -701,8 +715,8 @@ impl ApplicationsKey {
// Get default icon subkey
let default_icon_key = match regext::try_open_subkey_with_flags(
&key,
Self::NAMEOF_DEFAULT_ICON_PART1,
KEY_READ,
regext::blank_path_guard(Self::NAMEOF_DEFAULT_ICON_PART1)?,
PERM_R,
)? {
Some(key) => key,
None => return Ok(None),
@@ -725,8 +739,8 @@ impl ApplicationsKey {
Some(icon) => {
// Create default icon subkey
let (default_icon_key, _) = key.create_subkey_with_flags(
Self::NAMEOF_DEFAULT_ICON_PART1,
KEY_READ | KEY_WRITE,
regext::blank_path_guard(Self::NAMEOF_DEFAULT_ICON_PART1)?,
PERM_RW,
)?;
// Set default value of default icon subkey.
default_icon_key.set_value(Self::NAMEOF_DEFAULT_ICON_PART2, &icon.to_string())?;
@@ -774,7 +788,25 @@ impl ApplicationsKey {
const NAMEOF_SUPPORTED_TYPES: &str = "SupportedTypes";
pub fn get_supported_types(&self, view: View) -> Result<Option<Vec<concept::Ext>>, Error> {
todo!()
let key = self.open_view_for_getter(view)?;
// Get supported types subkey
let supported_types_key = match regext::try_open_subkey_with_flags(
&key,
regext::blank_path_guard(Self::NAMEOF_SUPPORTED_TYPES)?,
PERM_R,
)? {
Some(key) => key,
None => return Ok(None),
};
// Fetch all sub-values
let key_names = regext::get_all_string_subkey_names(&supported_types_key)?;
// Map the result
let exts = key_names
.into_iter()
.map(|name| name.parse::<concept::Ext>())
.collect::<Result<Vec<_>, _>>()?;
// Return value
Ok(Some(exts))
}
pub fn set_supported_types(
@@ -782,7 +814,29 @@ impl ApplicationsKey {
scope: Scope,
tys: Option<&[&concept::Ext]>,
) -> Result<(), Error> {
todo!()
let key = self.open_scope_for_setter(scope)?;
match tys {
Some(tys) => {
// Create supported types key
let (supported_types_key, _) = key.create_subkey_with_flags(
regext::blank_path_guard(Self::NAMEOF_SUPPORTED_TYPES)?,
PERM_RW,
)?;
// Clean all contents of this key
regext::clean_all_contents(&supported_types_key)?;
// Add file types one by one
for ty in tys {
supported_types_key.set_value(ty.dotted_inner(), &"")?;
}
}
None => {
// Delete this subkey.
key.delete_subkey_all(regext::blank_path_guard(Self::NAMEOF_SUPPORTED_TYPES)?)?;
}
}
Ok(())
}
const NAMEOF_NO_OPEN_WITH: &str = "NoOpenWith";
@@ -837,10 +891,7 @@ impl ExtKey {
// check privilege
check_privilege(territory, purpose)?;
// Fetch the permission
let perms = match purpose {
OpenKeyPurpose::Read => KEY_READ,
OpenKeyPurpose::ReadWrite => KEY_READ | KEY_WRITE,
};
let perms = purpose.to_permission();
// navigate to extension container
let hk = match territory {
@@ -850,9 +901,11 @@ impl ExtKey {
};
let classes = match territory {
OpenKeyTerritory::User | OpenKeyTerritory::System => {
hk.open_subkey_with_flags(Self::FULL_CLASSES, perms)?
hk.open_subkey_with_flags(regext::blank_path_guard(Self::FULL_CLASSES)?, perms)?
}
OpenKeyTerritory::Hybrid => {
hk.open_subkey_with_flags(regext::blank_path_guard(Self::PARTIAL_CLASSES)?, perms)?
}
OpenKeyTerritory::Hybrid => hk.open_subkey_with_flags(Self::PARTIAL_CLASSES, perms)?,
};
// open extension key if possible
let this_ext = regext::try_open_subkey_with_flags(
@@ -882,7 +935,7 @@ impl ExtKey {
if let None = key.this_key {
let _ = key.parent_key.create_subkey_with_flags(
regext::blank_path_guard(self.ext.dotted_inner())?,
KEY_READ | KEY_WRITE,
PERM_RW,
)?;
Ok(true)
} else {
@@ -919,11 +972,28 @@ impl ExtKey {
const NAMEOF_DEFAULT: &str = "";
pub fn get_default(&self, view: View) -> Result<Option<LosseProgId>, Error> {
todo!()
let key = self.open_view_for_getter(view)?;
// Get value of it
let value = regext::try_get_value::<String, _>(&key, Self::NAMEOF_DEFAULT)?;
// Transform it as result
Ok(value.map(|v| LosseProgId::from(v.as_str())))
}
pub fn set_default(&mut self, scope: Scope, pid: Option<&LosseProgId>) -> Result<(), Error> {
todo!()
let key = self.open_scope_for_setter(scope)?;
match pid {
Some(pid) => {
// Set value for this key
key.set_value(Self::NAMEOF_DEFAULT, &pid.to_string())?;
}
None => {
// Delete this key
key.delete_value(Self::NAMEOF_DEFAULT)?;
}
}
Ok(())
}
const NAMEOF_OPEN_WITH_PROGIDS: &str = "OpenWithProgIds";
@@ -984,10 +1054,7 @@ impl ProgIdKey {
// check privilege
check_privilege(territory, purpose)?;
// Fetch the permission
let perms = match purpose {
OpenKeyPurpose::Read => KEY_READ,
OpenKeyPurpose::ReadWrite => KEY_READ | KEY_WRITE,
};
let perms = purpose.to_permission();
// navigate to ProgId container
let hk = match territory {
@@ -997,9 +1064,11 @@ impl ProgIdKey {
};
let classes = match territory {
OpenKeyTerritory::User | OpenKeyTerritory::System => {
hk.open_subkey_with_flags(Self::FULL_CLASSES, perms)?
hk.open_subkey_with_flags(regext::blank_path_guard(Self::FULL_CLASSES)?, perms)?
}
OpenKeyTerritory::Hybrid => {
hk.open_subkey_with_flags(regext::blank_path_guard(Self::PARTIAL_CLASSES)?, perms)?
}
OpenKeyTerritory::Hybrid => hk.open_subkey_with_flags(Self::PARTIAL_CLASSES, perms)?,
};
// open ProgId key if possible
let this_progid = regext::try_open_subkey_with_flags(
@@ -1029,7 +1098,7 @@ impl ProgIdKey {
if let None = key.this_key {
let _ = key.parent_key.create_subkey_with_flags(
regext::blank_path_guard(self.progid.to_string())?,
KEY_READ | KEY_WRITE,
PERM_RW,
)?;
Ok(true)
} else {

View File

@@ -104,6 +104,15 @@ pub fn get_all_string_subkey_names(regkey: &RegKey) -> std::io::Result<Vec<Strin
.collect::<Result<Vec<_>, _>>()
}
/// Delete all contents, including values and subkeys of given key.
///
/// Deleting all contents of given key rely on giving a special parameter to [RegKey::delete_subkey_all].
/// This is very dangerous and may be used by accident.
/// So I create this to explicitly indicate this behavior and avoid any mis-type in code.
pub fn clean_all_contents(regkey: &RegKey) -> std::io::Result<()> {
regkey.delete_subkey_all("")
}
// endregion
// region: Blank Path Guard