doc: add docstrings for win32 module

This commit is contained in:
2026-06-25 21:47:38 +08:00
parent 3492f93c83
commit 23d7045ec1
3 changed files with 191 additions and 28 deletions

View File

@@ -32,6 +32,12 @@ impl BadExtBodyError {
/// The struct representing an file extension which must start with dot (`.`) /// The struct representing an file extension which must start with dot (`.`)
/// and followed by at least one arbitrary characters. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ext { pub struct Ext {
/// The body of file extension (excluding dot). /// The body of file extension (excluding dot).
@@ -135,13 +141,18 @@ impl BadProgIdPartError {
/// The ProgId exactly follows Microsoft suggested /// The ProgId exactly follows Microsoft suggested
/// `[Vendor or Application].[Component].[Version]` format. /// `[Vendor or Application].[Component].[Version]` format.
/// And additionally, `[Version]` part is optional.
/// ///
/// Additionally, `[Version]` part is optional. /// In reality world, most of applications do no follow this standard.
/// /// However, this scenario is not convered by this struct in there.
/// However, most of applications do no follow this standard,
/// this scenario is not convered by this struct in there.
/// It should be done by other structs in other places. /// 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: /// Reference:
/// - https://learn.microsoft.com/en-us/windows/win32/shell/fa-progids /// - https://learn.microsoft.com/en-us/windows/win32/shell/fa-progids
/// - https://learn.microsoft.com/en-us/windows/win32/com/-progid--key /// - 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). /// `{26EE0668-A00A-44D7-9371-BEB064C98683}` (case insensitive).
/// ///
/// Please note that the curly brace is the essential part of CLSID. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Clsid { pub struct Clsid {
inner: Uuid, 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 /// The struct representing an Icon Reference String
/// looks like `%SystemRoot%\System32\imageres.dll,-72`. /// looks like `%SystemRoot%\System32\imageres.dll,-72`.
/// ///
/// As far as I know, the minus token `-` does nothing in this string. /// As far as I know, the minus token `-` does nothing in this string.
/// The following number is just the index. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IconRefStr { pub struct IconRefStr {
/// The path part of this reference string. /// The path part of this reference string.
@@ -360,6 +390,12 @@ impl IconRefStr {
/// Get the path part of this reference string. /// Get the path part of this reference string.
/// ///
/// This path can be absolute path, relative path or expandable path. /// 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 { pub fn get_path(&self) -> &str {
&self.path &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 /// The struct representing an String Reference String
/// looks like `@%SystemRoot%\System32\shell32.dll,-30596`. /// looks like `@%SystemRoot%\System32\shell32.dll,-30596`.
/// ///
/// As far as I know, the minus token `-` does nothing in this string. /// As far as I know, the minus token `-` does nothing in this string.
/// The following number is just the index. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StrRefStr { pub struct StrRefStr {
/// The path part of this reference string. /// The path part of this reference string.
@@ -448,6 +495,12 @@ impl StrRefStr {
/// Get the path part of this reference string. /// Get the path part of this reference string.
/// ///
/// This path can be absolute path, relative path or expandable path. /// 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 { pub fn get_path(&self) -> &str {
&self.path &self.path
} }
@@ -512,7 +565,16 @@ pub enum IconSizeKind {
Large, 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)] #[derive(Debug)]
pub struct IconRc { pub struct IconRc {
icon: HICON, icon: HICON,
@@ -535,6 +597,9 @@ impl IconRc {
impl IconRc { impl IconRc {
/// Load icon from executable or `.ico` file. /// 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. /// 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. /// Otherwise `index` is the icon resource index located in executable.
pub fn new(file: &str, index: u32, kind: IconSizeKind) -> Result<Self, LoadIconRcError> { pub fn new(file: &str, index: u32, kind: IconSizeKind) -> Result<Self, LoadIconRcError> {
@@ -570,16 +635,28 @@ impl IconRc {
Self::new(file, 0, kind) 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 { pub unsafe fn from_raw(hicon: HICON) -> Self {
Self { icon: hicon } Self { icon: hicon }
} }
pub fn into_raw(self) -> HICON { /// Consume and leak this struct held Win32 icon handle.
self.icon ///
/// 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 { 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 { pub fn get_icon(&self) -> HICON {
self.icon self.icon
} }
@@ -630,12 +707,18 @@ pub enum LoadStrRcError {
} }
/// The struct representing a loaded string resource. /// The struct representing a loaded string resource.
///
/// You can use [StrRc::new] to create this resource.
#[derive(Debug)] #[derive(Debug)]
pub struct StrRc { pub struct StrRc {
inner: String, inner: String,
} }
impl StrRc { 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<Self, LoadStrRcError> { pub fn new(file: &str, index: u32) -> Result<Self, LoadStrRcError> {
use windows_sys::Win32::Foundation::FreeLibrary; use windows_sys::Win32::Foundation::FreeLibrary;
use windows_sys::Win32::System::LibraryLoader::{ use windows_sys::Win32::System::LibraryLoader::{
@@ -681,10 +764,12 @@ impl StrRc {
} }
impl StrRc { impl StrRc {
/// Get fetched string resource.
pub fn get_string(&self) -> &str { pub fn get_string(&self) -> &str {
&self.inner &self.inner
} }
/// Consume and return fetched string resource.
pub fn into_string(self) -> String { pub fn into_string(self) -> String {
self.inner self.inner
} }
@@ -725,9 +810,15 @@ pub enum ExpandEnvVarError {
NoEnvVar, NoEnvVar,
} }
/// The struct representing an Expand String, /// The struct representing an expandable string,
/// which contain environment variable in string, /// which contain environment variable in string,
/// like `%LOCALAPPDATA%\SomeApp.exe`. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ExpandString { pub struct ExpandString {
inner: String, inner: String,
@@ -745,7 +836,7 @@ impl ExpandString {
} }
/// Expand the variables located in this string /// 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<String, ExpandEnvVarError> { pub fn expand(&self) -> Result<String, ExpandEnvVarError> {
use windows_sys::Win32::System::Environment::ExpandEnvironmentStringsW; use windows_sys::Win32::System::Environment::ExpandEnvironmentStringsW;
@@ -809,6 +900,11 @@ impl FromStr for ExpandString {
pub type BadFileNameError = ParseFileNameError; pub type BadFileNameError = ParseFileNameError;
/// The struct representing a legal Windows file name. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileName { pub struct FileName {
/// The validated legal Windows file name. /// The validated legal Windows file name.
@@ -882,6 +978,11 @@ impl FromStr for FileName {
pub type BadVerbError = ParseVerbError; pub type BadVerbError = ParseVerbError;
/// The struct representing a verb when manipulating file /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Verb { pub struct Verb {
/// The validated verb name. /// The validated verb name.
@@ -964,6 +1065,10 @@ impl FromStr for Verb {
// region: Command Line // 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. /// The error occurs when constructing CmdLine with bad arguments.
#[derive(Debug, TeError)] #[derive(Debug, TeError)]
#[error("given file extension body \"{inner}\" is invalid")] #[error("given file extension body \"{inner}\" is invalid")]
@@ -973,30 +1078,68 @@ pub struct BadCmdLineError {
/// The struct representing a Windows command line. /// The struct representing a Windows command line.
/// ///
/// # Note /// 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.
///
/// # Todo
/// ///
/// This struct currently does nothing for validation for given command line. /// This struct currently does nothing for validation for given command line.
/// Because there is no standard for validating this. /// Because there is no standard for validating this.
/// So I just write this struct as a placeholder for future extension. /// 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CmdLine { pub struct CmdLine {
inner: Vec<String>, inner: Vec<String>,
} }
impl CmdLine { 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<S: AsRef<str>>(args: &[S]) -> Result<Self, BadCmdLineError> { pub fn new<S: AsRef<str>>(args: &[S]) -> Result<Self, BadCmdLineError> {
Ok(Self { Ok(Self {
inner: args.iter().map(|s| s.as_ref().to_string()).collect(), 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 { pub fn full(&self) -> String {
self.inner.join(" ") self.inner.join(" ")
} }
/// Get the iterator of command line arguments. /// 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<Item = &str> { pub fn iter(&self) -> impl Iterator<Item = &str> {
self.inner.iter().map(|s| s.as_str()) self.inner.iter().map(|s| s.as_str())
} }
@@ -1010,6 +1153,10 @@ pub struct ParseCmdLineError {
} }
impl ParseCmdLineError { impl ParseCmdLineError {
// TODO: Remove this dead_code attribute once we need use this error type.
#[allow(dead_code)]
fn new(inner: &str) -> Self { fn new(inner: &str) -> Self {
Self { Self {
inner: inner.to_string(), inner: inner.to_string(),
@@ -1033,3 +1180,5 @@ impl FromStr for CmdLine {
}) })
} }
} }
// endregion

View File

@@ -1,8 +1,6 @@
//! This module extend `winreg` crate to make it more suit for the usage of this crate. //! This module extend `winreg` crate to make it more suit for the usage of this crate.
use std::ffi::OsStr; use std::ffi::OsStr;
use std::ops::Deref;
use std::ops::DerefMut;
use thiserror::Error as TeError; use thiserror::Error as TeError;
use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND; use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND;
use windows_sys::Win32::System::Registry::REG_SAM_FLAGS; use windows_sys::Win32::System::Registry::REG_SAM_FLAGS;
@@ -12,13 +10,13 @@ use winreg::types::FromRegValue;
// region: Extra Operations // 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(...)`, /// If error occurs when fetching given subkey, it return `Err(...)`,
/// otherwise, it will return `Ok(Some(...))` if subkey is existing, /// otherwise, it will return `Ok(Some(...))` if subkey is existing,
/// or `Ok(None)` if there is no suchsub key. /// 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. /// it differ "no such subkey" error and other access error.
pub fn try_open_subkey_with_flags<P: AsRef<OsStr>>( pub fn try_open_subkey_with_flags<P: AsRef<OsStr>>(
regkey: &RegKey, regkey: &RegKey,
@@ -37,13 +35,13 @@ pub fn try_open_subkey_with_flags<P: AsRef<OsStr>>(
} }
} }
/// Get the value by given key. /// Try getting the value by given key.
/// ///
/// If error occurs when fetching given key, it return `Err(...)`, /// If error occurs when fetching given key, it return `Err(...)`,
/// otherwise, it will return `Ok(Some(...))` if key is existing, /// otherwise, it will return `Ok(Some(...))` if key is existing,
/// or `Ok(None)` if there is no such key. /// 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. /// it differ "no such key" error and other access error.
pub fn try_get_value<T: FromRegValue, N: AsRef<OsStr>>( pub fn try_get_value<T: FromRegValue, N: AsRef<OsStr>>(
regkey: &RegKey, regkey: &RegKey,
@@ -109,13 +107,17 @@ pub fn arbitrarily_delete_value<N: AsRef<OsStr>>(
} }
} }
// 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. /// 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 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 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<Option<String>> { pub fn get_sole_subkey_name(regkey: &RegKey) -> std::io::Result<Option<String>> {
let mut subkey_enumerator = regkey.enum_keys(); let mut subkey_enumerator = regkey.enum_keys();
@@ -134,7 +136,7 @@ pub fn get_sole_subkey_name(regkey: &RegKey) -> std::io::Result<Option<String>>
/// Get the name list of all "string" subkeys in given key. /// 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<Vec<String>> { pub fn get_all_string_subkey_names(regkey: &RegKey) -> std::io::Result<Vec<String>> {
regkey regkey
.enum_values() .enum_values()
@@ -180,15 +182,15 @@ impl BlankPathError {
} }
/// Check whether given registry path is empty. /// 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. /// Passing empty path for some [winreg] functions is dangerous, expecially for those registry delete functions.
/// Because it will cause unexpected behavior that returning key self, rather than subkey. /// Passing empty path to registry creation function will return themselves,
/// This is VERY dangerous especially for those registry delete functions. /// 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 registry function. /// 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, /// This function MUST be used for wrapping 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. /// if that value will be passed to get/set value, or create/delete key functions.
pub fn blank_path_guard<P: AsRef<OsStr>>(path: P) -> std::result::Result<P, BlankPathError> { pub fn blank_path_guard<P: AsRef<OsStr>>(path: P) -> std::result::Result<P, BlankPathError> {
if path.as_ref().is_empty() { if path.as_ref().is_empty() {
Err(BlankPathError::new()) Err(BlankPathError::new())
@@ -201,6 +203,11 @@ pub fn blank_path_guard<P: AsRef<OsStr>>(path: P) -> std::result::Result<P, Blan
// region: Expand String // region: Expand String
// TODO:
// Re-enable following code when we need to distinguish between REG_SZ and REG_EXPAND_SZ.
/*
/// The struct basically is the alias of String, but make a slight difference with it, /// The struct basically is the alias of String, but make a slight difference with it,
/// to make they are different when use it with String as generic argument. /// to make they are different when use it with String as generic argument.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -268,4 +275,6 @@ impl From<&str> for ExpandString {
} }
} }
*/
// endregion // endregion

View File

@@ -8,6 +8,11 @@
/// Return true if it is, otherwise false. /// Return true if it is, otherwise false.
/// ///
/// Reference: https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership /// 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 { pub fn has_privilege() -> bool {
use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Security::{ use windows_sys::Win32::Security::{