Compare commits
2 Commits
119a4d0341
...
447d94fdd6
| Author | SHA1 | Date | |
|---|---|---|---|
| 447d94fdd6 | |||
| f0bd2c0b73 |
@@ -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)?;
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -62,7 +62,7 @@ impl AppPathsKey {
|
||||
Ok(key.is_some())
|
||||
}
|
||||
|
||||
/// Ensure this application key is presented in App Paths.
|
||||
/// Ensure this application key is presented in App Paths key.
|
||||
///
|
||||
/// Return true if we newly create this key,
|
||||
/// otherwise false indicating there already is an existing key.
|
||||
@@ -79,15 +79,16 @@ impl AppPathsKey {
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete this application key from App Paths.
|
||||
/// Delete this application key from App Paths key.
|
||||
///
|
||||
/// If there is no such key in App Paths,
|
||||
/// this function does nothing.
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<()> {
|
||||
/// Return true if we successfully delete this key,
|
||||
/// otherwise false indicating there is no such key (already deleted).
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
key.parent_key
|
||||
.delete_subkey_all(regext::blank_path_guard(self.key_name.inner())?)?;
|
||||
Ok(())
|
||||
Ok(regext::arbitrarily_delete_subkey_all(
|
||||
&key.parent_key,
|
||||
regext::blank_path_guard(self.key_name.inner())?,
|
||||
)?)
|
||||
}
|
||||
|
||||
fn open_scope_for_getter(&self, scope: Scope) -> Result<RegKey> {
|
||||
|
||||
@@ -68,6 +68,10 @@ impl ApplicationsKey {
|
||||
Ok(key.is_some())
|
||||
}
|
||||
|
||||
/// Ensure this application key is presented in Applications key.
|
||||
///
|
||||
/// Return true if we newly create this key,
|
||||
/// otherwise false indicating there already is an existing key.
|
||||
pub fn ensure(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
if let None = key.this_key {
|
||||
@@ -81,11 +85,16 @@ impl ApplicationsKey {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<()> {
|
||||
/// Delete this application key from Applications key.
|
||||
///
|
||||
/// Return true if we successfully delete this key,
|
||||
/// otherwise false indicating there is no such key (already deleted).
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
key.parent_key
|
||||
.delete_subkey_all(regext::blank_path_guard(self.key_name.inner())?)?;
|
||||
Ok(())
|
||||
Ok(regext::arbitrarily_delete_subkey_all(
|
||||
&key.parent_key,
|
||||
regext::blank_path_guard(self.key_name.inner())?,
|
||||
)?)
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
@@ -176,7 +185,7 @@ impl ApplicationsKey {
|
||||
}
|
||||
None => {
|
||||
// Delete shell and its all subkey.
|
||||
key.delete_subkey_all(Self::NAMEOF_SHELL_VERB_PART1)?;
|
||||
regext::arbitrarily_delete_subkey_all(&key, Self::NAMEOF_SHELL_VERB_PART1)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +226,7 @@ impl ApplicationsKey {
|
||||
}
|
||||
None => {
|
||||
// Delete shell and its all subkey.
|
||||
key.delete_subkey_all(Self::NAMEOF_DEFAULT_ICON_PART1)?;
|
||||
regext::arbitrarily_delete_subkey_all(&key, Self::NAMEOF_DEFAULT_ICON_PART1)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,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)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +307,7 @@ impl ApplicationsKey {
|
||||
}
|
||||
None => {
|
||||
// Delete this subkey.
|
||||
key.delete_subkey_all(Self::NAMEOF_SUPPORTED_TYPES)?;
|
||||
regext::arbitrarily_delete_subkey_all(&key, Self::NAMEOF_SUPPORTED_TYPES)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,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(())
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ impl ExtKey {
|
||||
Ok(key.is_some())
|
||||
}
|
||||
|
||||
/// Ensure this file extension key is presented in Classes key.
|
||||
///
|
||||
/// Return true if we newly create this key,
|
||||
/// otherwise false indicating there already is an existing key.
|
||||
pub fn ensure(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
if let None = key.this_key {
|
||||
@@ -79,11 +83,16 @@ impl ExtKey {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<()> {
|
||||
/// Delete this file extension key from Classes key.
|
||||
///
|
||||
/// Return true if we successfully delete this key,
|
||||
/// otherwise false indicating there is no such key (already deleted).
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
key.parent_key
|
||||
.delete_subkey_all(regext::blank_path_guard(self.ext.dotted_inner())?)?;
|
||||
Ok(())
|
||||
Ok(regext::arbitrarily_delete_subkey_all(
|
||||
&key.parent_key,
|
||||
regext::blank_path_guard(self.ext.dotted_inner())?,
|
||||
)?)
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
@@ -127,7 +136,7 @@ impl ExtKey {
|
||||
}
|
||||
None => {
|
||||
// Delete this key
|
||||
key.delete_value(Self::NAMEOF_DEFAULT)?;
|
||||
regext::arbitrarily_delete_value(&key, Self::NAMEOF_DEFAULT)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ impl ProgIdKey {
|
||||
Ok(key.is_some())
|
||||
}
|
||||
|
||||
/// Ensure this ProgId key is presented in Classes key.
|
||||
///
|
||||
/// Return true if we newly create this key,
|
||||
/// otherwise false indicating there already is an existing key.
|
||||
pub fn ensure(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
if let None = key.this_key {
|
||||
@@ -79,11 +83,16 @@ impl ProgIdKey {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<()> {
|
||||
/// Delete this ProgId key from Classes key.
|
||||
///
|
||||
/// Return true if we successfully delete this key,
|
||||
/// otherwise false indicating there is no such key (already deleted).
|
||||
pub fn delete(&mut self, scope: Scope) -> Result<bool> {
|
||||
let key = self.open_scope_for_write(scope)?;
|
||||
key.parent_key
|
||||
.delete_subkey_all(regext::blank_path_guard(self.progid.to_string())?)?;
|
||||
Ok(())
|
||||
Ok(regext::arbitrarily_delete_subkey_all(
|
||||
&key.parent_key,
|
||||
regext::blank_path_guard(self.progid.to_string())?,
|
||||
)?)
|
||||
}
|
||||
|
||||
// YYC MARK:
|
||||
@@ -129,7 +138,7 @@ impl ProgIdKey {
|
||||
}
|
||||
None => {
|
||||
// Delete this key
|
||||
key.delete_value(Self::NAMEOF_DEFAULT)?;
|
||||
regext::arbitrarily_delete_value(&key, Self::NAMEOF_DEFAULT)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +218,7 @@ impl ProgIdKey {
|
||||
}
|
||||
None => {
|
||||
// Delete shell and its all subkey.
|
||||
key.delete_subkey_all(Self::NAMEOF_SHELL_VERB_PART1)?;
|
||||
regext::arbitrarily_delete_subkey_all(&key, Self::NAMEOF_SHELL_VERB_PART1)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,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)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +293,7 @@ impl ProgIdKey {
|
||||
}
|
||||
None => {
|
||||
// Delete shell and its all subkey.
|
||||
key.delete_subkey_all(Self::NAMEOF_DEFAULT_ICON_PART1)?;
|
||||
regext::arbitrarily_delete_subkey_all(&key, Self::NAMEOF_DEFAULT_ICON_PART1)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,54 @@ pub fn try_get_value<T: FromRegValue, N: AsRef<OsStr>>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete all tree of given path of given key anyway.
|
||||
///
|
||||
/// 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.
|
||||
/// Oppositely, [RegKey::delete_subkey_all] will return error if there is no such path.
|
||||
///
|
||||
/// Return true if we successfully delete this key,
|
||||
/// otherwise false indicating there is no such key (already deleted).
|
||||
pub fn arbitrarily_delete_subkey_all<P: AsRef<OsStr>>(
|
||||
regkey: &RegKey,
|
||||
path: P,
|
||||
) -> std::io::Result<bool> {
|
||||
match regkey.delete_subkey_all(path) {
|
||||
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),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@@ -110,6 +158,9 @@ pub fn get_all_string_subkey_names(regkey: &RegKey) -> std::io::Result<Vec<Strin
|
||||
/// 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<()> {
|
||||
// There is no possibility that this key do not existing,
|
||||
// because what we are cleaning is self content.
|
||||
// So directly use delete_subkey_all is okey.
|
||||
regkey.delete_subkey_all("")
|
||||
}
|
||||
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
@@ -75,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());
|
||||
@@ -177,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());
|
||||
@@ -246,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> =
|
||||
|
||||
Reference in New Issue
Block a user