feat: write some lowlevel code
This commit is contained in:
@@ -57,7 +57,10 @@ fn run_status(program: wfassoc::Program, view: wfassoc::View) -> Result<()> {
|
|||||||
|
|
||||||
fn run_ext_link(program: wfassoc::Program, scope: wfassoc::Scope, exts: Vec<String>) -> Result<()> {
|
fn run_ext_link(program: wfassoc::Program, scope: wfassoc::Scope, exts: Vec<String>) -> Result<()> {
|
||||||
let exts = stringified_exts_to_indices(&program, exts)?;
|
let exts = stringified_exts_to_indices(&program, exts)?;
|
||||||
todo!()
|
for index in exts {
|
||||||
|
program.link_ext(scope, index)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ext_unlink(
|
fn run_ext_unlink(
|
||||||
@@ -66,7 +69,10 @@ fn run_ext_unlink(
|
|||||||
exts: Vec<String>,
|
exts: Vec<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let exts = stringified_exts_to_indices(&program, exts)?;
|
let exts = stringified_exts_to_indices(&program, exts)?;
|
||||||
todo!()
|
for index in exts {
|
||||||
|
program.link_ext(scope, index)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ext_list(
|
fn run_ext_list(
|
||||||
|
|||||||
@@ -263,6 +263,18 @@ impl Program {
|
|||||||
pub fn is_registered(&self, view: View) -> Result<bool, ProgramError> {
|
pub fn is_registered(&self, view: View) -> Result<bool, ProgramError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn link_ext(&self, scope: Scope, index: usize) -> Result<(), ProgramError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlink_ext(&self, scope: Scope, index: usize) -> Result<(), ProgramError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ext_status(&self, view: View, index: usize) -> Result<(), ProgramError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
use crate::win32;
|
use crate::win32::{concept, regext, utilities};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use thiserror::Error as TeError;
|
use thiserror::Error as TeError;
|
||||||
use winreg::RegKey;
|
use winreg::RegKey;
|
||||||
|
use winreg::enums::{
|
||||||
|
HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
// region: Error Type
|
// region: Error Type
|
||||||
|
|
||||||
/// Error occurs in this module.
|
/// Error occurs in this module.
|
||||||
#[derive(Debug, TeError)]
|
#[derive(Debug, TeError)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("can not perform this operation because lack essential privilege.")]
|
#[error("can not perform this operation because lack essential privilege")]
|
||||||
NoPrivilege,
|
NoPrivilege,
|
||||||
#[error("{0}")]
|
#[error("given registry key is inexistant")]
|
||||||
|
InexistantKey,
|
||||||
|
#[error("registry operation error: {0}")]
|
||||||
BadRegOp(#[from] std::io::Error),
|
BadRegOp(#[from] std::io::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
UnexpectedBlankKey(#[from] win32::regext::BlankPathError),
|
UnexpectedBlankKey(#[from] regext::BlankPathError),
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@@ -78,7 +83,7 @@ impl Scope {
|
|||||||
/// Check whether we have enough privilege when operating in current scope.
|
/// Check whether we have enough privilege when operating in current scope.
|
||||||
/// If we have, simply return, otherwise return error.
|
/// If we have, simply return, otherwise return error.
|
||||||
fn check_privilege(&self) -> Result<(), Error> {
|
fn check_privilege(&self) -> Result<(), Error> {
|
||||||
if matches!(self, Self::System if !win32::utilities::has_privilege()) {
|
if matches!(self, Self::System if !utilities::has_privilege()) {
|
||||||
Err(Error::NoPrivilege)
|
Err(Error::NoPrivilege)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -88,20 +93,161 @@ impl Scope {
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region: Utilities
|
||||||
|
|
||||||
|
/// The purpose of opening this key.
|
||||||
|
enum OpenScopePurpose {
|
||||||
|
/// Only read something.
|
||||||
|
Read,
|
||||||
|
/// Need to write something.
|
||||||
|
ReadWrite,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal used struct representing the result of opening scope or view.
|
||||||
|
struct OpenedKey {
|
||||||
|
/// The parent key of opened key which must be presented.
|
||||||
|
parent_key: RegKey,
|
||||||
|
/// The opened key which may not be presented in registry.
|
||||||
|
this_key: Option<RegKey>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpenedKey {
|
||||||
|
fn new(parent_key: RegKey, this_key: Option<RegKey>) -> Self {
|
||||||
|
Self {
|
||||||
|
parent_key,
|
||||||
|
this_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
// region: App Paths Key
|
// region: App Paths Key
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct AppPathsKey {
|
pub struct AppPathsKey {
|
||||||
key: win32::concept::FileName,
|
key_name: concept::FileName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppPathsKey {
|
impl AppPathsKey {
|
||||||
pub fn new(inner: win32::concept::FileName) -> Self {
|
pub fn new(inner: concept::FileName) -> Self {
|
||||||
Self { key: inner }
|
Self { key_name: inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &win32::concept::FileName {
|
pub fn inner(&self) -> &concept::FileName {
|
||||||
&self.key
|
&self.key_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppPathsKey {
|
||||||
|
const APP_PATHS: &str = "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths";
|
||||||
|
|
||||||
|
fn open_scope(&self, scope: Scope, purpose: OpenScopePurpose) -> Result<OpenedKey, Error> {
|
||||||
|
// check privilege
|
||||||
|
if let OpenScopePurpose::ReadWrite = purpose {
|
||||||
|
scope.check_privilege()?;
|
||||||
|
}
|
||||||
|
// Fetch the permission
|
||||||
|
let perms = match purpose {
|
||||||
|
OpenScopePurpose::Read => KEY_READ,
|
||||||
|
OpenScopePurpose::ReadWrite => KEY_READ | KEY_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// get the root key
|
||||||
|
let hk = match scope {
|
||||||
|
Scope::User => RegKey::predef(HKEY_CURRENT_USER),
|
||||||
|
Scope::System => RegKey::predef(HKEY_LOCAL_MACHINE),
|
||||||
|
};
|
||||||
|
// navigate to App Paths
|
||||||
|
let app_paths = hk.open_subkey_with_flags(Self::APP_PATHS, perms)?;
|
||||||
|
// open file name key if possible
|
||||||
|
let this_app = regext::try_open_subkey_with_flags(
|
||||||
|
&app_paths,
|
||||||
|
regext::blank_path_guard(self.key_name.inner())?,
|
||||||
|
perms,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// okey
|
||||||
|
Ok(OpenedKey::new(app_paths, this_app))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_scope_for_read(&self, scope: Scope) -> Result<OpenedKey, Error> {
|
||||||
|
self.open_scope(scope, OpenScopePurpose::Read)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_scope_for_write(&self, scope: Scope) -> Result<OpenedKey, Error> {
|
||||||
|
self.open_scope(scope, OpenScopePurpose::ReadWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_exist(&self, scope: Scope) -> Result<bool, Error> {
|
||||||
|
let key = self.open_scope_for_read(scope)?.this_key;
|
||||||
|
Ok(key.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure this application key is presented in App Paths.
|
||||||
|
///
|
||||||
|
/// 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, Error> {
|
||||||
|
let key = self.open_scope_for_write(scope)?;
|
||||||
|
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,
|
||||||
|
)?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete this application key from App Paths.
|
||||||
|
///
|
||||||
|
/// If there is no such key in App Paths,
|
||||||
|
/// this function does nothing.
|
||||||
|
pub fn delete(&mut self, scope: Scope) -> Result<(), Error> {
|
||||||
|
let key = self.open_scope_for_write(scope)?;
|
||||||
|
key.parent_key
|
||||||
|
.delete_subkey_all(regext::blank_path_guard(self.key_name.inner())?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_scope_for_getter(&self, scope: Scope) -> Result<RegKey, Error> {
|
||||||
|
self.open_scope_for_read(scope)?
|
||||||
|
.this_key
|
||||||
|
.ok_or(Error::InexistantKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_scope_for_setter(&self, scope: Scope) -> Result<RegKey, Error> {
|
||||||
|
self.open_scope_for_write(scope)?
|
||||||
|
.this_key
|
||||||
|
.ok_or(Error::InexistantKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
const NAMEOF_PATH_TO_APPLICATION: &str = "";
|
||||||
|
|
||||||
|
pub fn get_path_to_application(&self, scope: Scope) -> Result<String, Error> {
|
||||||
|
let key = self.open_scope_for_getter(scope)?;
|
||||||
|
Ok(key.get_value(Self::NAMEOF_PATH_TO_APPLICATION)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_path_to_application(&mut self, scope: Scope, value: &str) -> Result<(), Error> {
|
||||||
|
let key = self.open_scope_for_setter(scope)?;
|
||||||
|
key.set_value(Self::NAMEOF_PATH_TO_APPLICATION, &value)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const NAMEOF_APPLICATION_DIRECTORY: &str = "Path";
|
||||||
|
|
||||||
|
pub fn get_application_directory(&self, scope: Scope) -> Result<String, Error> {
|
||||||
|
let key = self.open_scope_for_getter(scope)?;
|
||||||
|
Ok(key.get_value(Self::NAMEOF_APPLICATION_DIRECTORY)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_application_directory(&mut self, scope: Scope, value: &str) -> Result<(), Error> {
|
||||||
|
let key = self.open_scope_for_setter(scope)?;
|
||||||
|
key.set_value(Self::NAMEOF_APPLICATION_DIRECTORY, &value)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,16 +257,120 @@ impl AppPathsKey {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ApplicationsKey {
|
pub struct ApplicationsKey {
|
||||||
key: win32::concept::FileName,
|
key_name: concept::FileName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationsKey {
|
impl ApplicationsKey {
|
||||||
pub fn new(inner: win32::concept::FileName) -> Self {
|
pub fn new(inner: concept::FileName) -> Self {
|
||||||
Self { key: inner }
|
Self { key_name: inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &win32::concept::FileName {
|
pub fn inner(&self) -> &concept::FileName {
|
||||||
&self.key
|
&self.key_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationsKey {
|
||||||
|
const FULL_APPLICATIONS: &str = "Software\\Classes\\Applications";
|
||||||
|
const PARTIAL_APPLICATIONS: &str = "Applications";
|
||||||
|
|
||||||
|
fn open_scope(&self, scope: Scope, purpose: OpenScopePurpose) -> Result<OpenedKey, Error> {
|
||||||
|
// check privilege
|
||||||
|
if let OpenScopePurpose::ReadWrite = purpose {
|
||||||
|
scope.check_privilege()?;
|
||||||
|
}
|
||||||
|
// Fetch the permission
|
||||||
|
let perms = match purpose {
|
||||||
|
OpenScopePurpose::Read => KEY_READ,
|
||||||
|
OpenScopePurpose::ReadWrite => KEY_READ | KEY_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// get the root key
|
||||||
|
let hk = match scope {
|
||||||
|
Scope::User => RegKey::predef(HKEY_CURRENT_USER),
|
||||||
|
Scope::System => RegKey::predef(HKEY_LOCAL_MACHINE),
|
||||||
|
};
|
||||||
|
// navigate to Applications
|
||||||
|
let applications = hk.open_subkey_with_flags(Self::FULL_APPLICATIONS, perms)?;
|
||||||
|
// open extension key if possible
|
||||||
|
let this_app = regext::try_open_subkey_with_flags(
|
||||||
|
&applications,
|
||||||
|
regext::blank_path_guard(self.key_name.inner())?,
|
||||||
|
perms,
|
||||||
|
)?;
|
||||||
|
// okey
|
||||||
|
Ok(OpenedKey::new(applications, this_app))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_view(&self, view: View) -> Result<OpenedKey, Error> {
|
||||||
|
// define the permission
|
||||||
|
let perms = KEY_READ;
|
||||||
|
|
||||||
|
// navigate to extension container
|
||||||
|
let hk = match view {
|
||||||
|
View::User => RegKey::predef(HKEY_CURRENT_USER),
|
||||||
|
View::System => RegKey::predef(HKEY_LOCAL_MACHINE),
|
||||||
|
View::Hybrid => RegKey::predef(HKEY_CLASSES_ROOT),
|
||||||
|
};
|
||||||
|
let applications = match view {
|
||||||
|
View::User | View::System => {
|
||||||
|
hk.open_subkey_with_flags(Self::FULL_APPLICATIONS, perms)?
|
||||||
|
}
|
||||||
|
View::Hybrid => hk.open_subkey_with_flags(Self::PARTIAL_APPLICATIONS, perms)?,
|
||||||
|
};
|
||||||
|
// open extension key if possible
|
||||||
|
let this_app = regext::try_open_subkey_with_flags(
|
||||||
|
&applications,
|
||||||
|
regext::blank_path_guard(self.key_name.inner())?,
|
||||||
|
perms,
|
||||||
|
)?;
|
||||||
|
// okey
|
||||||
|
Ok(OpenedKey::new(applications, this_app))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_view_for_read(&self, view: View) -> Result<OpenedKey, Error> {
|
||||||
|
self.open_view(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_scope_for_write(&self, scope: Scope) -> Result<OpenedKey, Error> {
|
||||||
|
self.open_scope(scope, OpenScopePurpose::ReadWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_exist(&self, view: View) -> Result<bool, Error> {
|
||||||
|
let key = self.open_view_for_read(view)?.this_key;
|
||||||
|
Ok(key.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensure(&mut self, scope: Scope) -> Result<bool, Error> {
|
||||||
|
let key = self.open_scope_for_write(scope)?;
|
||||||
|
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,
|
||||||
|
)?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(&mut self, scope: Scope) -> Result<(), Error> {
|
||||||
|
let key = self.open_scope_for_write(scope)?;
|
||||||
|
key.parent_key
|
||||||
|
.delete_subkey_all(regext::blank_path_guard(self.key_name.inner())?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_view_for_getter(&self, view: View) -> Result<RegKey, Error> {
|
||||||
|
self.open_view_for_read(view)?
|
||||||
|
.this_key
|
||||||
|
.ok_or(Error::InexistantKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_scope_for_setter(&self, scope: Scope) -> Result<RegKey, Error> {
|
||||||
|
self.open_scope_for_write(scope)?
|
||||||
|
.this_key
|
||||||
|
.ok_or(Error::InexistantKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,10 +380,12 @@ impl ApplicationsKey {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ExtKey {
|
pub struct ExtKey {
|
||||||
ext: win32::concept::Ext,
|
ext: concept::Ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtKey {
|
impl ExtKey {
|
||||||
|
const CLASSES: &str = "Software\\Classes";
|
||||||
|
|
||||||
fn open_scope(&self, scope: Scope) -> Result<Option<RegKey>, Error> {
|
fn open_scope(&self, scope: Scope) -> Result<Option<RegKey>, Error> {
|
||||||
use winreg::enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE};
|
use winreg::enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE};
|
||||||
|
|
||||||
@@ -145,15 +397,15 @@ impl ExtKey {
|
|||||||
Scope::System => RegKey::predef(HKEY_LOCAL_MACHINE),
|
Scope::System => RegKey::predef(HKEY_LOCAL_MACHINE),
|
||||||
};
|
};
|
||||||
// navigate to classes
|
// navigate to classes
|
||||||
let classes = hk.open_subkey_with_flags("Software\\Classes", KEY_READ | KEY_WRITE)?;
|
let classes = hk.open_subkey_with_flags(Self::CLASSES, KEY_READ | KEY_WRITE)?;
|
||||||
// open extension key if possible
|
// open extension key if possible
|
||||||
let thisext = win32::regext::try_open_subkey_with_flags(
|
let this_ext = regext::try_open_subkey_with_flags(
|
||||||
&classes,
|
&classes,
|
||||||
win32::regext::blank_path_guard(self.ext.dotted_inner())?,
|
regext::blank_path_guard(self.ext.dotted_inner())?,
|
||||||
KEY_READ | KEY_WRITE,
|
KEY_READ | KEY_WRITE,
|
||||||
)?;
|
)?;
|
||||||
// okey
|
// okey
|
||||||
Ok(thisext)
|
Ok(this_ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_view(&self, view: View) -> Result<Option<RegKey>, Error> {
|
fn open_view(&self, view: View) -> Result<Option<RegKey>, Error> {
|
||||||
@@ -166,30 +418,26 @@ impl ExtKey {
|
|||||||
View::Hybrid => RegKey::predef(HKEY_CLASSES_ROOT),
|
View::Hybrid => RegKey::predef(HKEY_CLASSES_ROOT),
|
||||||
};
|
};
|
||||||
let classes = match view {
|
let classes = match view {
|
||||||
View::User | View::System => {
|
View::User | View::System => hk.open_subkey_with_flags(Self::CLASSES, KEY_READ)?,
|
||||||
hk.open_subkey_with_flags("Software\\Classes", KEY_READ)?
|
|
||||||
}
|
|
||||||
View::Hybrid => hk.open_subkey_with_flags("", KEY_READ)?,
|
View::Hybrid => hk.open_subkey_with_flags("", KEY_READ)?,
|
||||||
};
|
};
|
||||||
// open extension key if possible
|
// open extension key if possible
|
||||||
let thisext = win32::regext::try_open_subkey_with_flags(
|
let this_ext = regext::try_open_subkey_with_flags(
|
||||||
&classes,
|
&classes,
|
||||||
win32::regext::blank_path_guard(self.ext.dotted_inner())?,
|
regext::blank_path_guard(self.ext.dotted_inner())?,
|
||||||
KEY_READ,
|
KEY_READ,
|
||||||
)?;
|
)?;
|
||||||
// okey
|
// okey
|
||||||
Ok(thisext)
|
Ok(this_ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtKey {
|
impl ExtKey {
|
||||||
pub fn new(inner: win32::concept::Ext) -> Self {
|
pub fn new(inner: concept::Ext) -> Self {
|
||||||
Self { ext: inner }
|
Self { ext: inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &win32::concept::Ext {
|
pub fn inner(&self) -> &concept::Ext {
|
||||||
&self.ext
|
&self.ext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,7 +456,7 @@ impl ExtKey {
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum LosseProgId {
|
pub enum LosseProgId {
|
||||||
Plain(String),
|
Plain(String),
|
||||||
Strict(win32::concept::ProgId),
|
Strict(concept::ProgId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for LosseProgId {
|
impl Display for LosseProgId {
|
||||||
@@ -223,7 +471,7 @@ impl Display for LosseProgId {
|
|||||||
impl From<&str> for LosseProgId {
|
impl From<&str> for LosseProgId {
|
||||||
fn from(s: &str) -> Self {
|
fn from(s: &str) -> Self {
|
||||||
// match it for standard ProgId first
|
// match it for standard ProgId first
|
||||||
if let Ok(v) = win32::concept::ProgId::from_str(s) {
|
if let Ok(v) = concept::ProgId::from_str(s) {
|
||||||
Self::Strict(v)
|
Self::Strict(v)
|
||||||
} else {
|
} else {
|
||||||
// fallback with other
|
// fallback with other
|
||||||
@@ -232,6 +480,12 @@ impl From<&str> for LosseProgId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<concept::ProgId> for LosseProgId {
|
||||||
|
fn from(value: concept::ProgId) -> Self {
|
||||||
|
Self::Strict(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region: ProgId Key
|
// region: ProgId Key
|
||||||
|
|||||||
Reference in New Issue
Block a user