1
0

fix: add arbitrarily_delete_value and fix various bugs for lowlevel and highlevel

This commit is contained in:
2026-05-29 09:46:59 +08:00
parent f0bd2c0b73
commit 447d94fdd6
9 changed files with 65 additions and 20 deletions

View File

@@ -402,6 +402,7 @@ impl Program {
// Add this progid to file extension "open with" list. // Add this progid to file extension "open with" list.
let ext_key = &mut program_key.ext_key; let ext_key = &mut program_key.ext_key;
ext_key.ensure(scope)?;
ext_key.add_into_open_with_progids(scope, progid_key.inner())?; ext_key.add_into_open_with_progids(scope, progid_key.inner())?;
} }
@@ -438,9 +439,12 @@ impl Program {
// there is no need to reset the default open way of file extension. // there is no need to reset the default open way of file extension.
// So we simply remove it from "open with" list. // So we simply remove it from "open with" list.
// Remove this ProgId from file extension "open with" list. // Remove this ProgId from file extension "open with" list,
// if this file extension is existing
let ext_key = &mut program_key.ext_key; let ext_key = &mut program_key.ext_key;
ext_key.remove_from_open_with_progids(scope, progid_key.inner())?; if ext_key.is_exist(scope.into())? {
ext_key.remove_from_open_with_progids(scope, progid_key.inner())?;
}
// Delete ProgId subkey // Delete ProgId subkey
progid_key.delete(scope)?; progid_key.delete(scope)?;

View File

@@ -156,7 +156,7 @@ impl Schema {
} }
pub(super) fn get_behavior(&self) -> Option<&str> { pub(super) fn get_behavior(&self) -> Option<&str> {
self.icon.as_ref().map(|v| v.as_str()) self.behavior.as_ref().map(|v| v.as_str())
} }
pub(super) fn get_strs(&self) -> &HashMap<String, String> { pub(super) fn get_strs(&self) -> &HashMap<String, String> {

View File

@@ -257,7 +257,7 @@ impl ApplicationsKey {
} }
None => { None => {
// Delete this key // Delete this key
key.delete_value(Self::NAMEOF_FRIENDLY_APP_NAME)?; regext::arbitrarily_delete_value(&key, Self::NAMEOF_FRIENDLY_APP_NAME)?;
} }
} }
@@ -329,7 +329,7 @@ impl ApplicationsKey {
if flag { if flag {
key.set_value(Self::NAMEOF_NO_OPEN_WITH, &"")?; key.set_value(Self::NAMEOF_NO_OPEN_WITH, &"")?;
} else { } else {
key.delete_value(Self::NAMEOF_NO_OPEN_WITH)?; regext::arbitrarily_delete_value(&key, Self::NAMEOF_NO_OPEN_WITH)?;
} }
Ok(()) Ok(())
} }

View File

@@ -136,7 +136,7 @@ impl ExtKey {
} }
None => { None => {
// Delete this key // Delete this key
key.delete_value(Self::NAMEOF_DEFAULT)?; regext::arbitrarily_delete_value(&key, Self::NAMEOF_DEFAULT)?;
} }
} }
@@ -214,7 +214,10 @@ impl ExtKey {
None => return Ok(()), None => return Ok(()),
}; };
// Remove given key // Remove given key
open_with_progids_key.delete_value(pid.to_string())?; regext::arbitrarily_delete_value(
&open_with_progids_key,
regext::blank_path_guard(pid.to_string())?,
)?;
Ok(()) Ok(())
} }
} }

View File

@@ -138,7 +138,7 @@ impl ProgIdKey {
} }
None => { None => {
// Delete this key // Delete this key
key.delete_value(Self::NAMEOF_DEFAULT)?; regext::arbitrarily_delete_value(&key, Self::NAMEOF_DEFAULT)?;
} }
} }
@@ -252,7 +252,7 @@ impl ProgIdKey {
} }
None => { None => {
// Delete this key // Delete this key
key.delete_value(Self::NAMEOF_FRIENDLY_TYPE_NAME)?; regext::arbitrarily_delete_value(&key, Self::NAMEOF_FRIENDLY_TYPE_NAME)?;
} }
} }

View File

@@ -66,7 +66,7 @@ pub fn try_get_value<T: FromRegValue, N: AsRef<OsStr>>(
/// This function was invented to fix the shortcoming of [RegKey::delete_subkey_all]. /// This function was invented to fix the shortcoming of [RegKey::delete_subkey_all].
/// This function always delete given path of given key no matter it is existing. /// This function always delete given path of given key no matter it is existing.
/// Oppositely, [RegKey::delete_subkey_all] will return error if there is no such path. /// Oppositely, [RegKey::delete_subkey_all] will return error if there is no such path.
/// ///
/// Return true if we successfully delete this key, /// Return true if we successfully delete this key,
/// otherwise false indicating there is no such key (already deleted). /// otherwise false indicating there is no such key (already deleted).
pub fn arbitrarily_delete_subkey_all<P: AsRef<OsStr>>( pub fn arbitrarily_delete_subkey_all<P: AsRef<OsStr>>(
@@ -85,6 +85,30 @@ pub fn arbitrarily_delete_subkey_all<P: AsRef<OsStr>>(
} }
} }
/// Delete given value key of given key anyway.
///
/// This function was invented to fix the shortcoming of [RegKey::delete_value].
/// This function always delete given value key of given key no matter it is existing.
/// Oppositely, [RegKey::delete_value] will return error if there is no such value key.
///
/// Return true if we successfully delete this value key,
/// otherwise false indicating there is no such value key (already deleted).
pub fn arbitrarily_delete_value<N: AsRef<OsStr>>(
regkey: &RegKey,
name: N,
) -> std::io::Result<bool> {
match regkey.delete_value(name) {
Ok(()) => Ok(true),
Err(e) => match e.raw_os_error() {
Some(errno) => match errno as u32 {
ERROR_FILE_NOT_FOUND => Ok(false),
_ => Err(e),
},
_ => Err(e),
},
}
}
/// 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 only one subkey in given key, the return value is its name.

View File

@@ -9,8 +9,19 @@ pub fn check_sandbox() {
std::env::var("SANDBOXIE").is_ok(), std::env::var("SANDBOXIE").is_ok(),
concat!( concat!(
"Non-sandbox environment detected. ", "Non-sandbox environment detected. ",
"Executing these test in non-sandbox environment is VERY dangerous. ", "Executing these tests in non-sandbox environment is VERY dangerous. ",
"Please set \"SANDBOXIE\" environment variable to explicitly indicate you are running these test in sandbox environment." "Please set \"SANDBOXIE\" environment variable to explicitly indicate you are running these tests in sandbox environment."
)
)
}
pub fn check_privilege() {
assert!(
wfassoc::win32::utilities::has_privilege(),
concat!(
"You are running test without privilege. ",
"These tests must be run with some privilege because it need to manipulate Windows Registry. ",
"Please give it privilege in your sandbox environment."
) )
) )
} }

View File

@@ -13,8 +13,8 @@ fn make_valid_schema() -> Schema {
schema.set_clsid(CLSID); schema.set_clsid(CLSID);
schema.add_str("main_name", "Passoc Application").unwrap(); schema.add_str("main_name", "Passoc Application").unwrap();
schema.add_str("ext_name", "Pacfg File").unwrap(); schema.add_str("ext_name", "Pacfg File").unwrap();
schema.add_icon("main_icon", r"notepad.exe,0").unwrap(); schema.add_icon("main_icon", "notepad.exe,0").unwrap();
schema.add_icon("ext_icon", r"notepad.exe,0").unwrap(); schema.add_icon("ext_icon", "notepad.exe,0").unwrap();
schema.add_behavior("main_behavior", "notepad.exe %1").unwrap(); schema.add_behavior("main_behavior", "notepad.exe %1").unwrap();
schema.add_behavior("ext_behavior", "notepad.exe %1").unwrap(); schema.add_behavior("ext_behavior", "notepad.exe %1").unwrap();
schema.set_name(Some("main_name")); schema.set_name(Some("main_name"));
@@ -29,21 +29,20 @@ fn make_valid_schema() -> Schema {
#[test] #[test]
fn test_schema() { fn test_schema() {
common::check_sandbox(); common::check_sandbox();
common::check_privilege();
// valid schema -> valid program // valid schema -> valid program
let schema = make_valid_schema(); let schema = make_valid_schema();
let rv = schema.into_program(); let rv = schema.into_program();
assert!(rv.is_ok()); assert!(rv.is_ok());
// missing identifier // missing essential parts (schema, path and etc)
let mut schema = Schema::new(); let schema = Schema::new();
schema.set_path(APP_PATH);
let rv = schema.into_program(); let rv = schema.into_program();
assert!(rv.is_err()); assert!(rv.is_err());
// invalid path // invalid path
let mut schema = Schema::new(); let mut schema = make_valid_schema();
schema.set_identifier(IDENTIFIER);
schema.set_path(r"C:\"); schema.set_path(r"C:\");
let rv = schema.into_program(); let rv = schema.into_program();
assert!(rv.is_err()); assert!(rv.is_err());
@@ -93,6 +92,7 @@ fn test_schema() {
#[test] #[test]
fn test_program() { fn test_program() {
common::check_sandbox(); common::check_sandbox();
common::check_privilege();
fn tester(scope: Scope, view: View) { fn tester(scope: Scope, view: View) {
// build program // build program

View File

@@ -22,6 +22,7 @@ static VERB: LazyLock<ShellVerb> = LazyLock::new(|| {
#[test] #[test]
fn test_app_paths_key() { fn test_app_paths_key() {
common::check_sandbox(); common::check_sandbox();
common::check_privilege();
static APP_PATH: &str = r"C:\Program Files\Passoc\passoc.exe"; static APP_PATH: &str = r"C:\Program Files\Passoc\passoc.exe";
static APP_DIR: &str = r"C:\Program Files\Passoc"; static APP_DIR: &str = r"C:\Program Files\Passoc";
@@ -31,7 +32,6 @@ fn test_app_paths_key() {
// delete and ensure // delete and ensure
let rv = key.delete(scope); let rv = key.delete(scope);
eprintln!("{rv:?}");
assert!(rv.is_ok()); assert!(rv.is_ok());
let rv = key.is_exist(scope); let rv = key.is_exist(scope);
assert!(rv.is_ok()); assert!(rv.is_ok());
@@ -76,6 +76,7 @@ fn test_app_paths_key() {
#[test] #[test]
fn test_applications_key() { fn test_applications_key() {
common::check_sandbox(); common::check_sandbox();
common::check_privilege();
static FRIENDLY_APP_NAME: LazyLock<StrResVariant> = static FRIENDLY_APP_NAME: LazyLock<StrResVariant> =
LazyLock::new(|| "Passoc Application".into()); LazyLock::new(|| "Passoc Application".into());
@@ -178,6 +179,7 @@ fn test_applications_key() {
#[test] #[test]
fn test_ext_key() { fn test_ext_key() {
common::check_sandbox(); common::check_sandbox();
common::check_privilege();
fn tester(scope: Scope, view: View) { fn tester(scope: Scope, view: View) {
let mut key = ExtKey::new(EXT.clone()); let mut key = ExtKey::new(EXT.clone());
@@ -247,6 +249,7 @@ fn test_ext_key() {
#[test] #[test]
fn test_prog_id_key() { fn test_prog_id_key() {
common::check_sandbox(); common::check_sandbox();
common::check_privilege();
static LEGACY_NAME: LazyLock<StrResVariant> = LazyLock::new(|| "Passoc Pacfg File".into()); static LEGACY_NAME: LazyLock<StrResVariant> = LazyLock::new(|| "Passoc Pacfg File".into());
static FRIENDLY_TYPE_NAME: LazyLock<StrResVariant> = static FRIENDLY_TYPE_NAME: LazyLock<StrResVariant> =