win_desktop_utils/lib.rs
1//! Windows-first desktop utility helpers for Rust apps.
2//!
3//! `win-desktop-utils` provides small, focused helpers for common Windows desktop-app
4//! tasks without forcing consumers to work directly with raw Win32 shell, mutex, and
5//! known-folder APIs.
6//!
7//! # Scope
8//!
9//! This crate currently provides helpers for:
10//!
11//! - opening files and directories with the default shell handler
12//! - opening URLs
13//! - revealing items in Explorer
14//! - sending files or directories to the Recycle Bin
15//! - enforcing single-instance behavior
16//! - resolving per-user app-data directories
17//! - creating per-user app-data directories if needed
18//! - checking elevation and relaunching as admin
19//!
20//! This crate is intended for Windows desktop applications and utilities.
21//! Some functions launch external shell behavior or may trigger a UAC prompt.
22//! This crate supports Windows only.
23//!
24//! # Current API
25//!
26//! - [`open_with_default`]
27//! - [`open_with_verb`]
28//! - [`open_url`]
29//! - [`reveal_in_explorer`]
30//! - [`move_to_recycle_bin`]
31//! - [`move_paths_to_recycle_bin`]
32//! - [`single_instance`]
33//! - [`single_instance_with_scope`]
34//! - [`roaming_app_data`]
35//! - [`local_app_data`]
36//! - [`ensure_roaming_app_data`]
37//! - [`ensure_local_app_data`]
38//! - [`is_elevated`]
39//! - [`restart_as_admin`]
40//! - [`InstanceScope`]
41//!
42//! # Example
43//!
44//! ```
45//! fn main() -> Result<(), win_desktop_utils::Error> {
46//! let _guard = match win_desktop_utils::single_instance("demo-app")? {
47//! Some(guard) => guard,
48//! None => {
49//! println!("already running");
50//! return Ok(());
51//! }
52//! };
53//!
54//! let local = win_desktop_utils::ensure_local_app_data("demo-app")?;
55//! assert!(local.ends_with("demo-app"));
56//!
57//! Ok(())
58//! }
59//! ```
60//!
61//! # Behavior Notes
62//!
63//! - [`open_with_default`] requires a non-empty existing path.
64//! - [`open_with_verb`] uses `ShellExecuteW` with the requested shell verb.
65//! - [`open_url`] trims surrounding whitespace before delegating to the Windows shell.
66//! - [`reveal_in_explorer`] requires an existing path and launches `explorer.exe`.
67//! - [`move_to_recycle_bin`] requires an absolute existing path and uses `IFileOperation`
68//! on a dedicated STA thread for recycle-bin behavior.
69//! - [`move_paths_to_recycle_bin`] validates all paths before starting one shell
70//! recycle-bin operation.
71//! - [`roaming_app_data`] and [`local_app_data`] resolve their base directories via
72//! `SHGetKnownFolderPath`.
73//! - [`single_instance`] uses a `Local\...` named mutex, so the lock is scoped to the
74//! current Windows session, and `app_id` cannot contain backslashes.
75//! - [`single_instance_with_scope`] can opt into either the current-session or global
76//! mutex namespace.
77//! - [`restart_as_admin`] starts a new elevated instance of the current executable,
78//! does not terminate the current process, and rejects arguments containing NUL bytes.
79
80#[cfg(not(windows))]
81compile_error!("win-desktop-utils supports Windows only.");
82
83#[cfg(windows)]
84pub mod elevation;
85#[cfg(windows)]
86pub mod error;
87#[cfg(windows)]
88pub mod instance;
89#[cfg(windows)]
90pub mod paths;
91#[cfg(windows)]
92pub mod shell;
93
94#[cfg(windows)]
95pub use error::{Error, Result};
96
97#[cfg(windows)]
98pub use elevation::{is_elevated, restart_as_admin};
99#[cfg(windows)]
100pub use instance::{single_instance, single_instance_with_scope, InstanceGuard, InstanceScope};
101#[cfg(windows)]
102pub use paths::{ensure_local_app_data, ensure_roaming_app_data, local_app_data, roaming_app_data};
103#[cfg(windows)]
104pub use shell::{
105 move_paths_to_recycle_bin, move_to_recycle_bin, open_url, open_with_default, open_with_verb,
106 reveal_in_explorer,
107};