Skip to content

Windows CTRL_CLOSE not working? #122

@diogovalada

Description

@diogovalada

Adding the ctrlc crate to Cargo.toml with the termination feature, I tested the code below.

I compiled with cargo build and then run it by double clicking the executable. Then, when the console spawns, click the X Close button.

With the ctrlc version, the code didn't work as expected. I expected, after closing the console, for both the X.txt and m_X.txt to keep being saved every second, for 5 seconds. However, when I clicked close, they both stop printing right away. The ctrl handler only prints a single file, m_1.txt.

I managed to get it work properly with the winapi version, commented in the code below. To test that, just comment the ctrlc code and uncommented that one.

What am I doing wrong?

main.rs

use ctrlc;
use std::fs::File;
use std::io::Write;
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};
use std::{thread, time::Duration};
use winapi::shared::minwindef::{BOOL, TRUE};
use winapi::um::consoleapi::SetConsoleCtrlHandler; // SetConsoleCtrlHandler is in consoleapi module



//============================ rust-ctrlc version =======================================


fn register_ctrl_handler(exit_flag: Arc<AtomicBool>) {
    ctrlc::set_handler(move || {
        let handler_start_time = std::time::Instant::now();

        for _ in 0..30 {
            let elapsed_secs = handler_start_time.elapsed().as_secs();
            let file_name = format!("m_{}.txt", elapsed_secs);
            File::create(&file_name);
            thread::sleep(Duration::from_secs(1));
        }

        exit_flag.store(true, Ordering::SeqCst);
        println!("Handler finished execution.");
    })
    .expect("Error setting up CTRL+C handler");
}

fn main() {
    let start_time = std::time::Instant::now();
    let exit_flag = Arc::new(AtomicBool::new(false));
    register_ctrl_handler(Arc::clone(&exit_flag));

    while !exit_flag.load(Ordering::SeqCst) {
        let elapsed_secs = start_time.elapsed().as_secs();
        let file_name = format!("{}.txt", elapsed_secs);
        let mut file = File::create(&file_name).expect("Unable to create file");
        writeln!(file, "Elapsed seconds: {}", elapsed_secs).expect("Unable to write to file");
        println!("Saved file: {}", file_name);
        thread::sleep(Duration::from_secs(1));
    }

    println!("Program exited gracefully.");
}

// ==================================== WINAPI version =======================================

// unsafe extern "system" fn ctrl_handler(_ctrl_type: u32) -> BOOL {
//     println!("CTRL+C detected. Handler started...");
//     let handler_start_time = std::time::Instant::now();

//     for i in 0..30 {
//         let elapsed_secs = handler_start_time.elapsed().as_secs();
//         let file_name = format!("m_{}.txt", elapsed_secs);
//         File::create(&file_name);
//         thread::sleep(Duration::from_secs(1));
//     }

//     println!("Handler finished execution.");
//     TRUE
// }

// fn register_ctrl_handler(_exit_flag: Arc<AtomicBool>) {
//     unsafe {
//         if SetConsoleCtrlHandler(Some(ctrl_handler), TRUE) == 0 {
//             panic!("Error setting up CTRL+C handler");
//         }
//     }
// }

// fn main() {
//     let start_time = std::time::Instant::now();
//     let exit_flag = Arc::new(AtomicBool::new(false));
//     register_ctrl_handler(Arc::clone(&exit_flag));

//     while !exit_flag.load(Ordering::SeqCst) {
//         let elapsed_secs = start_time.elapsed().as_secs();
//         let file_name = format!("{}.txt", elapsed_secs);
//         let mut file = File::create(&file_name).expect("Unable to create file");
//         writeln!(file, "Elapsed seconds: {}", elapsed_secs).expect("Unable to write to file");
//         println!("Saved file: {}", file_name);
//         thread::sleep(Duration::from_secs(1));
//     }

//     println!("Program exited gracefully.");
// }

Cargo.toml

[package]
name = "rust-thread"
version = "0.1.0"
edition = "2021"

[dependencies]
winapi ={version = "*", features = ["wincon", "minwindef", "consoleapi"]}
ctrlc = { version = "*", features = ["termination"] }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions