Skip to main content

pacenotes_installer/
single_instance.rs

1const MUTEX_NAME: &str = "Local\\PacenotesInstaller.SingleInstance";
2/// How long a restarted instance waits for the one that launched it to close.
3const RESTART_WAIT_MS: u32 = 10_000;
4const RESTART_POLL_MS: u32 = 100;
5
6/// Whether another copy is running for this user, since two would share the
7/// download temp files, `cache.json` and a game folder's ledger unguarded.
8///
9/// A named mutex needs no cleanup after a crash. `Local\` scopes it to the
10/// logon session, because `Global\` needs a privilege a standard user may lack.
11/// The handle that wins is never closed, so the name lives as long as the
12/// process; one that finds the name taken is, or it would keep the mutex alive
13/// after its owner exits.
14pub fn another_instance_running() -> bool {
15    let name = crate::i18n::to_wide(MUTEX_NAME);
16    let take_ownership = 1;
17    unsafe {
18        let handle = windows_sys::Win32::System::Threading::CreateMutexW(
19            core::ptr::null(),
20            take_ownership,
21            name.as_ptr(),
22        );
23        // A failed check must not block the run on a machine with an unusual policy.
24        if handle.is_null() {
25            return false;
26        }
27        let taken = windows_sys::Win32::Foundation::GetLastError()
28            == windows_sys::Win32::Foundation::ERROR_ALREADY_EXISTS;
29        if taken {
30            windows_sys::Win32::Foundation::CloseHandle(handle);
31        }
32        taken
33    }
34}
35
36/// `another_instance_running` for an instance restarted as administrator, which
37/// starts while the one that launched it is still closing.
38pub fn another_instance_outlasts_restart() -> bool {
39    let mut waited = 0;
40    while another_instance_running() {
41        if waited >= RESTART_WAIT_MS {
42            return true;
43        }
44        std::thread::sleep(std::time::Duration::from_millis(u64::from(RESTART_POLL_MS)));
45        waited += RESTART_POLL_MS;
46    }
47    false
48}