Skip to main content

Crate windows_thread_ambient_sys

Crate windows_thread_ambient_sys 

Source
Expand description

Capture a Windows thread’s ambient state and apply it on another thread.

Some Windows behaviour is not a parameter of the call you make; it is ambient state hanging off the calling thread. An impersonation token decides whose access rights an open is checked against, and even which drive letters resolve. The thread error mode decides whether a hard device error raises a modal dialog. WOW64 filesystem redirection decides which of two directories a 32-bit process actually reaches. None of it travels with work handed to another thread.

That matters most when the other thread is shared. A thread-pool worker inherits none of the submitter’s ambient state: measured, OpenThreadToken on a worker returns ERROR_NO_TOKEN while the submitting thread genuinely held a token, and the worker’s error mode is 0, meaning the critical-error handler is enabled and an absent removable drive can put a modal dialog on process-shared infrastructure. Explicit capture is therefore necessary rather than merely prudent.

§Scope

This crate carries thread-scoped ambient state that changes what a Win32 call does. It does not carry call parameters, does not open files, and does not know what any particular Windows operation is.

§Two sets, because the aspects do not relate to the caller the same way

Aspects that can be read off the calling thread are captured, and which of them to collect is chosen by the caller. Aspects that cannot be read – WOW64 redirection has no getter at all, and I/O priority has no documented one – are declared instead: the caller states the value it wants installed. A declared aspect has nothing to collect, so it is not part of the capture set; left unspecified, it leaves the target thread’s own value alone.

§This crate holds no policy

Every aspect is offered for capture and for explicit declaration, and no combination is privileged. A consumer running on shared threads will want to force the dialog-suppressing error-mode bits; a consumer with a private thread, where a modal dialog is its own problem and nobody else’s, is entitled to the opposite choice. Both compose that policy from the primitives here rather than finding it already decided.

§Example

Capture on the submitting thread, where a failure is still the caller’s to see, then reconstruct the context on a worker that inherited none of it:

use std::thread;

use windows_thread_ambient_sys::declared::MemoryPriority;
use windows_thread_ambient_sys::{AmbientState, CaptureSet, Declared};

// Captured here, on the submitting thread, where a failure is still ours to
// see. Declared aspects are stated rather than read from anything.
let state = AmbientState::capture(CaptureSet::DEFAULT)?
    .with_declared(Declared::none().with_memory_priority(MemoryPriority::Low));

let applied = thread::spawn(move || {
    // Guards apply outermost-first and release in exact reverse, with
    // impersonation innermost because its window is the narrowest.
    state.with_applied(|| "ran as the submitter")
})
.join()
.expect("the worker did not panic")?;

assert_eq!(*applied.value(), "ran as the submitter");

// A restore failure for the reported aspects -- the error mode, the
// declared aspects, the transaction -- does not discard the operation's
// value; it arrives alongside it, so a caller can retire a contaminated
// thread without losing what the work produced.
assert!(applied.restore().is_clean());

Impersonation is deliberately not among those reported aspects: its restore is fail-fast, so a failure panics instead of being reported, and a panic inside a thread-pool callback aborts the process rather than failing one operation. That is the intended trade rather than an oversight, and it is the one property to weigh before adopting this crate on shared workers; state gives the reasoning in full.

A consumer that wants to override the error mode rather than transplant it – forcing the dialog-suppressing bits on a shared worker – leaves CaptureSet::ERROR_MODE out of its capture set and wraps the call in its own ThreadErrorMode::apply guard, which then sits outermost, exactly where the ordering puts it.

Re-exports§

pub use capture_set::CapturableAspect;
pub use capture_set::CaptureSet;
pub use captured::Captured;
pub use declared::Declared;
pub use state::AmbientState;
pub use state::Applied;
pub use state::ApplyError;
pub use state::ApplyFailure;
pub use state::CaptureError;
pub use state::CaptureFailure;
pub use state::RestoreReport;
pub use error_mode::ThreadErrorMode;

Modules§

capture_set
Which capturable aspects to collect.
captured
The three-state value every capturable aspect carries.
declared
The declared aspects: WOW64 filesystem redirection, memory priority, and I/O priority.
error_mode
The thread error mode aspect.
impersonation
The impersonation aspect.
state
The composite: a thread’s ambient state, captured as one value.
transaction
The TxF transaction aspect.

Structs§

ImpersonationToken
An owned, immutable snapshot of a Windows impersonation context.