#3694·windows-rs

`windows-services` using the service parameter in the closure passed to run with standard library threads

Author: adedominCreated Aug 1, 2025Updated Jul 7, 2026
Labelsquestion

Summary

I was experimenting with the latest release (0.25.0) of windows-services, but was struggling on how to use the service parameter passed to the callback. Rust rightfully points out I am leaking that parameter when I store the JoinHandle of the thread running my service code (so I can join it later). I saw the example but now I'm wondering if this is possible using the standard library's threads.

the compile error:

Compiling example-winsvc v0.1.0 (C:\Users\prussian\source\example-winsvc)
error[E0521]: borrowed data escapes outside of closure
  --> src\main.rs:10:21
   |
5  |         let mut thread = None;
   |             ---------- `thread` declared here, outside of the closure body
...
8  |             .run(|svc, comm| match comm {
   |                   --- `svc` is a reference that is only valid in the closure body
9  |                 windows_services::Command::Start if thread.is_none() => {
10 |                     thread = Some(s.spawn(|| {
   |                     ^^^^^^ `svc` escapes the closure body here

For more information about this error, try `rustc --explain E0521`.
error: could not compile `example-winsvc` (bin "example-winsvc") due to 1 previous error

Crate manifest

toml
[package]
name = "example-winsvc"
version = "0.1.0"
edition = "2024"

[dependencies]
windows-services = "0.25"

Crate code

rust
use windows_services::{Service, State};

fn main() {
    std::thread::scope(|s| {
        let mut thread = None;
        if Service::new()
            .can_stop()
            .run(|svc, comm| match comm {
                windows_services::Command::Start if thread.is_none() => {
                    thread = Some(s.spawn(|| {
                        println!("Hello, World!");
                        svc.set_state(State::Stopped);
                    }));
                }
                windows_services::Command::Stop => {
                    if let Some(jh) = thread.take() {
                        jh.join();
                    }
                }
                _ => (),
            })
            .is_err()
        {
            eprintln!("not running as service");
        };
    });
}