diff --git a/wfassoc/src/win32/concept.rs b/wfassoc/src/win32/concept.rs index 4897b1b..5e7a047 100644 --- a/wfassoc/src/win32/concept.rs +++ b/wfassoc/src/win32/concept.rs @@ -32,6 +32,12 @@ impl BadExtBodyError { /// The struct representing an file extension which must start with dot (`.`) /// and followed by at least one arbitrary characters. +/// +/// If you having a file extension expressed in string form with leading dot, +/// please utilize [FromStr] trait to build this struct. +/// Otherwise, use [Ext::new] with file extension without leading dot. +/// +/// The [Display] trait this struct implemented always outputs file extension with leading dot. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Ext { /// The body of file extension (excluding dot). @@ -135,13 +141,18 @@ impl BadProgIdPartError { /// The ProgId exactly follows Microsoft suggested /// `[Vendor or Application].[Component].[Version]` format. +/// And additionally, `[Version]` part is optional. /// -/// Additionally, `[Version]` part is optional. -/// -/// However, most of applications do no follow this standard, -/// this scenario is not convered by this struct in there. +/// In reality world, most of applications do no follow this standard. +/// However, this scenario is not convered by this struct in there. /// It should be done by other structs in other places. /// +/// If you have a ProgId expressed in string form, please utilize [FromStr] trait to parse it. +/// Or use [ProgId::new] with each parts to construct this struct. +/// +/// The [Display] trait this struct implemented always +/// outputs legal ProgId in string form. +/// /// Reference: /// - https://learn.microsoft.com/en-us/windows/win32/shell/fa-progids /// - https://learn.microsoft.com/en-us/windows/win32/com/-progid--key @@ -253,6 +264,14 @@ impl FromStr for ProgId { /// `{26EE0668-A00A-44D7-9371-BEB064C98683}` (case insensitive). /// /// Please note that the curly brace is the essential part of CLSID. +/// +/// If you have a CLSID expressed in string form, +/// please utilize [FromStr] trait to parse it. +/// You also can utilize [Clsid::new] with [uuid] crate to create a custom CLSID, +/// or directly use [Clsid::with_random] to create a random new one. +/// +/// The [Display] trait this struct implemented always +/// output CLSID in lower-case with curly brace. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Clsid { inner: Uuid, @@ -324,11 +343,22 @@ impl ParseIconRefStrError { } } +// TODO: +// IconRefStr should process the quote issue for path part in itself, +// rather than fetching its path part and resolve quote issue in another place. + /// The struct representing an Icon Reference String /// looks like `%SystemRoot%\System32\imageres.dll,-72`. /// /// As far as I know, the minus token `-` does nothing in this string. /// The following number is just the index. +/// +/// If you have a Icon Reference String, +/// please utilize [FromStr] trait to parse it into this struct. +/// You also can use [IconRefStr::new] with path and index parts to build this struct. +/// +/// The [Display] trait this struct implemented always +/// outputs Icon Reference String in string form. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct IconRefStr { /// The path part of this reference string. @@ -360,6 +390,12 @@ impl IconRefStr { /// Get the path part of this reference string. /// /// This path can be absolute path, relative path or expandable path. + /// + /// # Todo + /// + /// Currently this return value may be quoted path. + /// You may need manually unquote it. + /// This issue will be resolved in furture. pub fn get_path(&self) -> &str { &self.path } @@ -418,11 +454,22 @@ impl ParseStrRefStrError { } } +// TODO: +// StrRefStr should process the quote issue for path part in itself, +// rather than fetching its path part and resolve quote issue in another place. + /// The struct representing an String Reference String /// looks like `@%SystemRoot%\System32\shell32.dll,-30596`. /// /// As far as I know, the minus token `-` does nothing in this string. /// The following number is just the index. +/// +/// If you have a String Reference String, +/// please utilize [FromStr] trait to parse it into this struct. +/// You also can use [StrRefStr::new] with path and index parts to build this struct. +/// +/// The [Display] trait this struct implemented always +/// outputs String Reference String in string form. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StrRefStr { /// The path part of this reference string. @@ -448,6 +495,12 @@ impl StrRefStr { /// Get the path part of this reference string. /// /// This path can be absolute path, relative path or expandable path. + /// + /// # Todo + /// + /// Currently this return value may be quoted path. + /// You may need manually unquote it. + /// This issue will be resolved in furture. pub fn get_path(&self) -> &str { &self.path } @@ -512,7 +565,16 @@ pub enum IconSizeKind { Large, } -/// The struct representing a loaded icon resource. +/// The struct representing a loaded Win32 icon resource. +/// +/// You can use [IconRc::new] or [IconRc::with_ico_file] to create this resource. +/// +/// The ownership of loaded Win32 icon resource is managed by this struct, +/// and will be free once this struct was destroyed. +/// +/// According to Microsoft manual, +/// Win32 icon resource is program scope resource, +/// so it can be safely used between different threads. #[derive(Debug)] pub struct IconRc { icon: HICON, @@ -534,6 +596,9 @@ impl IconRc { impl IconRc { /// Load icon from executable or `.ico` file. + /// + /// Please note that the content of `file` parameter must NOT be + /// expandable string or quoted string. /// /// If you want to extract icon from `.ico` file, please pass `0` to `index` parameter. /// Otherwise `index` is the icon resource index located in executable. @@ -570,16 +635,28 @@ impl IconRc { Self::new(file, 0, kind) } + /// Construct this struct in raw Win32 icon handle. + /// + /// Please note that after calling this function, + /// the ownership of given Win32 icon handle are managed by this struct. pub unsafe fn from_raw(hicon: HICON) -> Self { Self { icon: hicon } } - pub fn into_raw(self) -> HICON { - self.icon + /// Consume and leak this struct held Win32 icon handle. + /// + /// The ownership of this Win32 icon handle will be transfered to the caller of this function. + pub fn into_raw(mut self) -> HICON { + let rv = self.icon; + self.icon = std::ptr::null_mut(); + rv } } impl IconRc { + /// Get underlying Win32 icon handle. + /// + /// Please note that the ownership of this handle are still in this struct. pub fn get_icon(&self) -> HICON { self.icon } @@ -630,12 +707,18 @@ pub enum LoadStrRcError { } /// The struct representing a loaded string resource. +/// +/// You can use [StrRc::new] to create this resource. #[derive(Debug)] pub struct StrRc { inner: String, } impl StrRc { + /// Load icon from executable file. + /// + /// Please note that the content of `file` parameter must NOT be + /// expandable string or quoted string. pub fn new(file: &str, index: u32) -> Result { use windows_sys::Win32::Foundation::FreeLibrary; use windows_sys::Win32::System::LibraryLoader::{ @@ -681,10 +764,12 @@ impl StrRc { } impl StrRc { + /// Get fetched string resource. pub fn get_string(&self) -> &str { &self.inner } + /// Consume and return fetched string resource. pub fn into_string(self) -> String { self.inner } @@ -725,9 +810,15 @@ pub enum ExpandEnvVarError { NoEnvVar, } -/// The struct representing an Expand String, +/// The struct representing an expandable string, /// which contain environment variable in string, /// like `%LOCALAPPDATA%\SomeApp.exe`. +/// +/// You can use [ExpandString::new] or [FromStr] trait to create an expandable string, +/// and use [ExpandString::expand] to try expanding it. +/// +/// The [Display] trait this struct implemented always +/// outputs original expandable string. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ExpandString { inner: String, @@ -745,7 +836,7 @@ impl ExpandString { } /// Expand the variables located in this string - /// and produce the final usable string. + /// and produce the final string without having any embedded variable syntax. pub fn expand(&self) -> Result { use windows_sys::Win32::System::Environment::ExpandEnvironmentStringsW; @@ -809,6 +900,11 @@ impl FromStr for ExpandString { pub type BadFileNameError = ParseFileNameError; /// The struct representing a legal Windows file name. +/// +/// You can utilize [FileName::new] or [FromStr] trait to create this struct. +/// +/// The [Display] trait this struct implemented always +/// outputs the file name in string form. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FileName { /// The validated legal Windows file name. @@ -882,6 +978,11 @@ impl FromStr for FileName { pub type BadVerbError = ParseVerbError; /// The struct representing a verb when manipulating file +/// +/// You can utilize [Verb::new] or [FromStr] trait to create this struct. +/// +/// The [Display] trait this struct implemented always +/// outputs the verb in string form. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Verb { /// The validated verb name. @@ -964,6 +1065,10 @@ impl FromStr for Verb { // region: Command Line +// TODO: +// Introduce CmdArg in future to describe single Windows command line argument. +// And use CmdArg to finish the full functionality of CmdLine. + /// The error occurs when constructing CmdLine with bad arguments. #[derive(Debug, TeError)] #[error("given file extension body \"{inner}\" is invalid")] @@ -972,31 +1077,69 @@ pub struct BadCmdLineError { } /// The struct representing a Windows command line. +/// +/// If you have a complete Windows command line expressed in string form, +/// you can utilize [FromStr] trait to create this struct. +/// Or, you can utilize [CmdLine::new] to create this struct with command arguments one by one. +/// +/// The [Display] trait this struct implemented always +/// outputs a legal Windows command line in string form, +/// which combine all arguments together. /// -/// # Note +/// # Todo /// /// This struct currently does nothing for validation for given command line. /// Because there is no standard for validating this. /// So I just write this struct as a placeholder for future extension. +/// +/// Currently if you are using [FromStr] trait to parse command line, +/// it will simply split it with space as separator. +/// This may cause unexpected behavior such as empty argument or unexpected break in argument. +/// This issue will be resolved in future. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct CmdLine { inner: Vec, } impl CmdLine { - /// Create a new command line. + /// Create a new command line with arguments one by one. + /// + /// Please note that passed command line argument must be unquoted. + /// + /// # Todo + /// + /// Currently, there is no unquote restrictions for those passed arguments. + /// These passed argument will be honestly used in full command line. + /// So if your argument require quote, please quote them at first. + /// This issue will be resolved in future. pub fn new>(args: &[S]) -> Result { Ok(Self { inner: args.iter().map(|s| s.as_ref().to_string()).collect(), }) } - /// Get the full command line. + /// Get the full command line in string form with proper quote. + /// + /// # Todo + /// + /// Currently this function only simply returns + /// the joined command line arguments with space as separator. + /// There is no guarantee about safe quote. + /// This issue will be resolved in future. pub fn full(&self) -> String { self.inner.join(" ") } /// Get the iterator of command line arguments. + /// + /// Each returned argument are unquoted. + /// + /// # Todo + /// + /// Currently there is no guarantee about the unquote behavior + /// for returned command line arguments. + /// It simply returns the content of arguments list passed to constructor. + /// This issue will be resolved in future. pub fn iter(&self) -> impl Iterator { self.inner.iter().map(|s| s.as_str()) } @@ -1010,6 +1153,10 @@ pub struct ParseCmdLineError { } impl ParseCmdLineError { + + // TODO: Remove this dead_code attribute once we need use this error type. + + #[allow(dead_code)] fn new(inner: &str) -> Self { Self { inner: inner.to_string(), @@ -1033,3 +1180,5 @@ impl FromStr for CmdLine { }) } } + +// endregion diff --git a/wfassoc/src/win32/regext.rs b/wfassoc/src/win32/regext.rs index 5bdf5da..8c6e65a 100644 --- a/wfassoc/src/win32/regext.rs +++ b/wfassoc/src/win32/regext.rs @@ -1,8 +1,6 @@ //! This module extend `winreg` crate to make it more suit for the usage of this crate. use std::ffi::OsStr; -use std::ops::Deref; -use std::ops::DerefMut; use thiserror::Error as TeError; use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND; use windows_sys::Win32::System::Registry::REG_SAM_FLAGS; @@ -12,13 +10,13 @@ use winreg::types::FromRegValue; // region: Extra Operations -/// Get the subkey with given name. +/// Try getting the subkey with given name. /// /// If error occurs when fetching given subkey, it return `Err(...)`, /// otherwise, it will return `Ok(Some(...))` if subkey is existing, /// or `Ok(None)` if there is no suchsub key. /// -/// Comparing with the function provided by winreg, +/// Comparing with the function provided by [winreg], /// it differ "no such subkey" error and other access error. pub fn try_open_subkey_with_flags>( regkey: &RegKey, @@ -37,13 +35,13 @@ pub fn try_open_subkey_with_flags>( } } -/// Get the value by given key. +/// Try getting the value by given key. /// /// If error occurs when fetching given key, it return `Err(...)`, /// otherwise, it will return `Ok(Some(...))` if key is existing, /// or `Ok(None)` if there is no such key. /// -/// Comparing with the function provided by winreg, +/// Comparing with the function provided by [winreg], /// it differ "no such key" error and other access error. pub fn try_get_value>( regkey: &RegKey, @@ -109,13 +107,17 @@ pub fn arbitrarily_delete_value>( } } +// TODO: +// Once we support multiple ShellVerb, +// it seems that there is no need to preserve this function. + /// 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 no any subkey, or has multiple subkeys, return None instead. -/// If error occurs when fetching data, return Err(_). +/// If error occurs when fetching data, return `Err(_)`. /// -/// This is usually used for ShellVerb fetching. +/// This is used as fetching only one ShellVerb. pub fn get_sole_subkey_name(regkey: &RegKey) -> std::io::Result> { let mut subkey_enumerator = regkey.enum_keys(); @@ -134,7 +136,7 @@ pub fn get_sole_subkey_name(regkey: &RegKey) -> std::io::Result> /// Get the name list of all "string" subkeys in given key. /// -/// This is usually used for "OpenWithProgIds" subkey. +/// This is used in "OpenWithProgIds" subkey. pub fn get_all_string_subkey_names(regkey: &RegKey) -> std::io::Result> { regkey .enum_values() @@ -180,15 +182,15 @@ impl BlankPathError { } /// Check whether given registry path is empty. -/// If it is, return error, otherwise the given path. +/// If it is, return error, otherwise the given path itself. /// -/// Passing empty path for some registry functions is dangerous. -/// Because it will cause unexpected behavior that returning key self, rather than subkey. -/// This is VERY dangerous especially for those registry delete functions. -/// So I create this function to prevent any harmful blank path was passed into registry function. +/// Passing empty path for some [winreg] functions is dangerous, expecially for those registry delete functions. +/// Passing empty path to registry creation function will return themselves, +/// and passing them to registry delete functions will delete all contents of them! +/// So I create this function to prevent any harmful blank path was passed into [winreg] function. /// -/// This function MUST be used for the value, whose content can not be confirmed at compile time, -/// and it will be passed to get/set value, or create/delete key functions. +/// This function MUST be used for wrapping the value, whose content can not be confirmed at compile time, +/// if that value will be passed to get/set value, or create/delete key functions. pub fn blank_path_guard>(path: P) -> std::result::Result { if path.as_ref().is_empty() { Err(BlankPathError::new()) @@ -201,6 +203,11 @@ pub fn blank_path_guard>(path: P) -> std::result::Result for ExpandString { } } +*/ + // endregion diff --git a/wfassoc/src/win32/utilities.rs b/wfassoc/src/win32/utilities.rs index e02381f..9356c0b 100644 --- a/wfassoc/src/win32/utilities.rs +++ b/wfassoc/src/win32/utilities.rs @@ -8,6 +8,11 @@ /// Return true if it is, otherwise false. /// /// Reference: https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership +/// +/// # Panics +/// +/// This function will panic if any Windows functions failed unexpectedly. +/// This is a very common check and in theory there is no any possibility that this check will fail. pub fn has_privilege() -> bool { use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Security::{