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.
let ext_key = &mut program_key.ext_key;
ext_key.ensure(scope)?;
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.
// 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;
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
progid_key.delete(scope)?;

View File

@@ -156,7 +156,7 @@ impl Schema {
}
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> {

View File

@@ -257,7 +257,7 @@ impl ApplicationsKey {
}
None => {
// 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 {
key.set_value(Self::NAMEOF_NO_OPEN_WITH, &"")?;
} else {
key.delete_value(Self::NAMEOF_NO_OPEN_WITH)?;
regext::arbitrarily_delete_value(&key, Self::NAMEOF_NO_OPEN_WITH)?;
}
Ok(())
}

View File

@@ -136,7 +136,7 @@ impl ExtKey {
}
None => {
// 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(()),
};
// 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(())
}
}

View File

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

View File

@@ -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.
///
/// 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(),
concat!(
"Non-sandbox environment detected. ",
"Executing these test in non-sandbox environment is VERY dangerous. ",
"Please set \"SANDBOXIE\" environment variable to explicitly indicate you are running these test in sandbox environment."
"Executing these tests in non-sandbox environment is VERY dangerous. ",
"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.add_str("main_name", "Passoc Application").unwrap();
schema.add_str("ext_name", "Pacfg File").unwrap();
schema.add_icon("main_icon", r"notepad.exe,0").unwrap();
schema.add_icon("ext_icon", r"notepad.exe,0").unwrap();
schema.add_icon("main_icon", "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("ext_behavior", "notepad.exe %1").unwrap();
schema.set_name(Some("main_name"));
@@ -29,21 +29,20 @@ fn make_valid_schema() -> Schema {
#[test]
fn test_schema() {
common::check_sandbox();
common::check_privilege();
// valid schema -> valid program
let schema = make_valid_schema();
let rv = schema.into_program();
assert!(rv.is_ok());
// missing identifier
let mut schema = Schema::new();
schema.set_path(APP_PATH);
// missing essential parts (schema, path and etc)
let schema = Schema::new();
let rv = schema.into_program();
assert!(rv.is_err());
// invalid path
let mut schema = Schema::new();
schema.set_identifier(IDENTIFIER);
let mut schema = make_valid_schema();
schema.set_path(r"C:\");
let rv = schema.into_program();
assert!(rv.is_err());
@@ -93,6 +92,7 @@ fn test_schema() {
#[test]
fn test_program() {
common::check_sandbox();
common::check_privilege();
fn tester(scope: Scope, view: View) {
// build program

View File

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