1
0

feat: write some highlevel code

This commit is contained in:
2026-04-23 13:17:25 +08:00
parent fed02ad9bc
commit 6ff42928f1
4 changed files with 166 additions and 8 deletions

View File

@@ -1,5 +1,8 @@
use crate::lowlevel;
use crate::{lowlevel, utilities, win32};
use std::collections::HashMap;
use std::ffi::OsStr;
use std::rc::Rc;
use std::path::Path;
use thiserror::Error as TeError;
pub use lowlevel::{Scope, View};
@@ -15,7 +18,16 @@ pub enum SchemaError {
/// Error occurs when trying converting `Schema` into `Program`.
#[derive(Debug, TeError)]
pub enum ParseProgramError {}
pub enum ParseProgramError {
#[error("{0}")]
BadFileName(#[from] win32::concept::BadFileNameError),
#[error("{0}")]
CastOsStr(#[from] utilities::CastOsStrError),
#[error("given path doesn't has legal file name part")]
NoFileNamePart,
#[error("given path doesn't has legal directory part")]
NoDirNamePart,
}
/// Error occurs when operating with `Program`.
#[derive(Debug, TeError)]
@@ -161,7 +173,20 @@ impl SchemaExt {
/// Program is a complete and immutable program representer
pub struct Program {
app_paths_key: lowlevel::AppPathsKey,
applications_key: lowlevel::ApplicationsKey,
file_name: String,
dir_name: String,
name: Rc<ProgramStr>,
icon: Rc<ProgramIcon>,
behavior: Rc<ProgramBehavior>,
strs: Vec<Rc<ProgramStr>>,
icons: Vec<Rc<ProgramIcon>>,
behaviors: Vec<Rc<ProgramBehavior>>,
progid_keys: Vec<Rc<ProgramProgIdKey>>,
ext_keys: Vec<ProgramExtKey>,
}
impl TryFrom<Schema> for Program {
@@ -173,15 +198,49 @@ impl TryFrom<Schema> for Program {
}
impl Program {
/// Extract the file name part from full path to application,
/// which was used in Registry path component.
fn extract_file_name(full_path: &Path) -> Result<&OsStr, ParseProgramError> {
full_path
.file_name()
.ok_or(ParseProgramError::NoFileNamePart)
}
/// Extract the start in path from full path to application,
/// which basically is the stem of full path.
fn extract_dir_name(full_path: &Path) -> Result<&OsStr, ParseProgramError> {
full_path
.parent()
.map(|p| p.as_os_str())
.ok_or(ParseProgramError::NoDirNamePart)
}
/// Try creating Program from Schema.
pub fn new(schema: Schema) -> Result<Self, ParseProgramError> {
todo!()
// Extract file name part and directory name part respectively.
let schema_path = Path::new(&schema.path);
let file_name = Self::extract_file_name(schema_path)?;
let file_name = String::from(utilities::osstr_to_str(file_name)?);
let dir_name = Self::extract_dir_name(schema_path)?;
let dir_name = String::from(utilities::osstr_to_str(dir_name)?);
// Build app paths key and applications key respectively
let key = win32::concept::FileName::new(&file_name)?;
let app_paths_key = lowlevel::AppPathsKey::new(key.clone());
let applications_key = lowlevel::ApplicationsKey::new(key.clone());
todo!();
// Ok(Self {
// app_paths_key,
// applications_key,
// file_name,
// dir_name,
// })
}
}
impl Program {
/// Register this application.
///
///
/// If there is registration of this application,
/// this function will return error.
pub fn register(&mut self, scope: Scope) -> Result<(), ProgramError> {
@@ -189,7 +248,7 @@ impl Program {
}
/// Unregister this application.
///
///
/// If there is no registration of this application,
/// this function will return error.
pub fn unregister(&mut self, scope: Scope) -> Result<(), ProgramError> {
@@ -199,6 +258,8 @@ impl Program {
/// Check whether this application has been registered in given view.
///
/// Please note that this is a rough check and do not validate any data.
///
/// The return value only ensures the pre-requirement of `register` and `unregister`.
pub fn is_registered(&self, view: View) -> Result<bool, ProgramError> {
todo!()
}
@@ -208,6 +269,41 @@ impl Program {
// region: Program Internals
/// Internal used enum presenting a Program string resource.
#[derive(Debug)]
enum ProgramStr {
Plain(String),
RefStr(win32::concept::StrRefStr)
}
/// Internal used enum presenting a Program icon resource.
#[derive(Debug)]
enum ProgramIcon {
Plain(String),
RefStr(win32::concept::IconRefStr)
}
/// Internal used enum presenting a Program behavior (command line setups).
#[derive(Debug)]
struct ProgramBehavior {
inner: String,
}
/// Internal used struct presenting a Program ProgId.
#[derive(Debug)]
struct ProgramProgIdKey {
key: lowlevel::ProgIdKey,
name: Rc<ProgramStr>,
icon: Rc<ProgramIcon>,
behavior: Rc<ProgramBehavior>,
}
/// Internal used struct presenting a Program file extension.
#[derive(Debug)]
struct ProgramExtKey {
key: lowlevel::ExtKey,
assoc: Rc<ProgramProgIdKey>
}
// endregion

View File

@@ -88,16 +88,44 @@ impl Scope {
// endregion
// region: App Paths Key
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AppPathsKey {
key: win32::concept::FileName,
}
impl AppPathsKey {
pub fn new(inner: win32::concept::FileName) -> Self {
Self { key: inner }
}
pub fn inner(&self) -> &win32::concept::FileName {
&self.key
}
}
// endregion
// region: Applications Key
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ApplicationsKey {
key: win32::concept::FileName,
}
impl ApplicationsKey {
pub fn new(inner: win32::concept::FileName) -> Self {
Self { key: inner }
}
pub fn inner(&self) -> &win32::concept::FileName {
&self.key
}
}
// endregion
// region: File Extension Key
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -156,6 +184,16 @@ impl ExtKey {
}
impl ExtKey {
pub fn new(inner: win32::concept::Ext) -> Self {
Self { ext: inner }
}
pub fn inner(&self) -> &win32::concept::Ext {
&self.ext
}
}
// endregion
// region: ProgId Key
@@ -164,11 +202,11 @@ impl ExtKey {
/// The enum representing a losse Programmatic Identifiers (ProgId).
///
/// In real world, not all software developers are willing to following Microsoft suggestions to use ProgId,
/// In real world, not all software developers are willing to following Microsoft suggestions to use ProgId.
/// They use string which do not have any regulation as ProgId.
/// This enum is designed for handling this scenario.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum LosseProgId {
pub enum LosseProgId {
Plain(String),
Strict(win32::concept::ProgId),
}
@@ -203,6 +241,16 @@ pub struct ProgIdKey {
progid: LosseProgId,
}
impl ProgIdKey {
pub fn new(inner: LosseProgId) -> Self {
Self { progid: inner }
}
pub fn inner(&self) -> &LosseProgId {
&self.progid
}
}
// endregion
// endregion

View File

@@ -321,6 +321,7 @@ impl ParseIconRefStrError {
///
/// As far as I know, the minus token `-` does nothing in this string.
/// The following number is just the index.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IconRefStr {
/// The path part of this reference string.
/// And it can be expandable.
@@ -414,6 +415,7 @@ impl ParseStrRefStrError {
///
/// As far as I know, the minus token `-` does nothing in this string.
/// The following number is just the index.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StrRefStr {
/// The path part of this reference string.
/// And it can be expandable.
@@ -503,6 +505,7 @@ pub enum IconSizeKind {
}
/// The struct representing a loaded icon resource.
#[derive(Debug)]
pub struct IconRc {
icon: HICON,
}
@@ -593,6 +596,7 @@ pub enum LoadStrRcError {
}
/// The struct representing a loaded string resource.
#[derive(Debug)]
pub struct StrRc {
inner: String,
}
@@ -686,6 +690,7 @@ pub enum ExpandEnvVarError {
/// The struct representing an Expand String,
/// which contain environment variable in string,
/// like `%LOCALAPPDATA%\SomeApp.exe`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ExpandString {
inner: String,
}
@@ -800,6 +805,8 @@ pub enum ParseFileNameError {
EmbeddedNul(#[from] widestring::error::ContainsNul<WideChar>),
/// Given string has illegal char as Windows file name.
InvalidChar,
/// Given string is empty.
EmptyStr,
}
impl Display for FileName {
@@ -814,7 +821,12 @@ impl FromStr for FileName {
fn from_str(s: &str) -> Result<Self, Self::Err> {
use windows_sys::Win32::UI::Shell::PathCleanupSpec;
// Make buffer and call function.
// If given string is empty, it must be illegal.
if s.is_empty() {
return Err(ParseFileNameError::EmptyStr);
}
// Make buffer and call Win32 function for checking.
let mut spec = WideCString::from_str(s)?;
let rv = unsafe { PathCleanupSpec(std::ptr::null(), spec.as_mut_ptr()) };
if rv != 0 {

View File

@@ -35,6 +35,7 @@ fn test_ext_parse() {
}
ok_tester(".jpg", "jpg");
err_tester(".");
err_tester(".jar.disabled");
err_tester("jar");
}
@@ -247,6 +248,7 @@ fn test_file_name() {
}
ok_tester("GoodExecutable.exe");
err_tester("");
err_tester("*.?xaml");
err_tester(r#"\\\lol///"#);
}