1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Safe blocking bindings to the Windows Restart Manager (`rstrtmgr.dll`).
//!
//! A primary [`RestartSession`] owns shutdown, restart, filter, and
//! cancellation capabilities. A secondary [`JoinedSession`] can only register
//! and inspect resources, making a role violation impossible to express.
//!
//! # Example
//!
//! ```rust,no_run
//! # #[cfg(windows)]
//! # fn main() -> Result<(), restart_manager::Error> {
//! use restart_manager::{RestartSession, ShutdownOptions};
//!
//! let mut session = RestartSession::new()?;
//! session.register_files([r"C:\some\locked\file.dll"])?;
//! let report = session.affected_applications()?;
//! for application in &report {
//! println!("locked by: {:?}", application.display_name());
//! }
//! let pending = session.shutdown_with_options(ShutdownOptions::default());
//! let can_update = pending.shutdown_outcome().is_success();
//! if can_update {
//! // Replace or update the registered files here.
//! }
//! let completion = pending.restart();
//! let outcome = completion.outcome().clone();
//! completion.end()?;
//! outcome.shutdown_outcome().clone().into_result()?;
//! outcome
//! .restart_outcome()
//! .expect("restart was attempted")
//! .clone()
//! .into_result()?;
//! # Ok(())
//! # }
//! # #[cfg(not(windows))]
//! # fn main() {}
//! ```
//!
//! Relative file and executable paths are made absolute, but this crate never
//! checks existence or canonicalizes them. Restart Manager does not support
//! registering directories. Forced shutdown is opt-in and can lose target
//! application data. Restart is only possible for services and applications
//! that registered for restart.
//!
//! Progress callbacks use a process-global native callback slot because the
//! Windows API supplies no context pointer. Concurrent callback-bearing calls
//! fail immediately with [`ErrorKind::CallbackInUse`]. A callback panic is
//! contained at the FFI boundary and resumed after Windows returns.
//!
//! # Platform support
//!
//! All domain and session types are available on every target. Pure input
//! validation behaves identically everywhere; operations that require Windows
//! return [`ErrorKind::UnsupportedPlatform`].
//!
//! # Typestate guarantees
//!
//! A joined installer cannot query or control the primary workflow:
//!
//! ```compile_fail
//! fn invalid(joined: &mut restart_manager::JoinedSession) {
//! let _ = joined.affected_applications();
//! }
//! ```
//!
//! Restart is not available before a shutdown attempt:
//!
//! ```compile_fail
//! fn invalid(session: restart_manager::RestartSession) {
//! let _ = session.restart();
//! }
//! ```
//!
//! A pending recovery state cannot register resources, manipulate filters, or
//! end the native session:
//!
//! ```compile_fail
//! fn invalid(mut pending: restart_manager::RestartPending) {
//! let batch = restart_manager::ResourceBatch::new();
//! let _ = pending.register_resources(&batch);
//! let _ = pending.end();
//! }
//! ```
//!
//! Consuming a state prevents a second operation on the same value:
//!
//! ```compile_fail
//! fn invalid(session: restart_manager::RestartSession) {
//! let _pending = session.shutdown();
//! let _ = session.end();
//! }
//! ```
pub use crate::;