こちらの記事にインスパイアされて、Windows だったらどう書くのかなというを残しておきます。
GUI アプリならEnumWindows
関数でウィンドウタイトルを調べて多重起動を防止してましたが、CUI アプリではどうするのか知りませんでした。どうやらCreateMutex
という WinAPI を使えば良いようです。
CreateMutexA function (synchapi.h) - Win32 apps | Microsoft Docs
Rust から WinAPI を呼ぶには winapi crate を使用します。
winapi - crates.io: Rust Package Registry
コードはこのようになるでしょうか。
Cargo.toml
[package]
name = "multiboot_lock"
version = "0.1.0"
authors = ["benki"]
edition = "2018"
[dependencies.winapi]
version = "0.3"
features = [
"errhandlingapi",
"handleapi",
"minwindef",
"ntdef",
"synchapi",
"winerror",
]
main.rs
use std::ptr;
use std::thread;
use std::time::Duration;
use winapi::{
shared::{minwindef::TRUE, ntdef::HANDLE, winerror::ERROR_ALREADY_EXISTS},
um::{
errhandlingapi::GetLastError,
handleapi::CloseHandle,
synchapi::{CreateMutexA, ReleaseMutex},
},
};
struct Handle(HANDLE);
impl Drop for Handle {
fn drop(&mut self) {
if !self.0.is_null() {
println!("後始末");
unsafe {
ReleaseMutex(self.0);
CloseHandle(self.0);
}
}
}
}
fn main() {
let handle = unsafe {
println!("Mutex の生成");
CreateMutexA(
ptr::null_mut(),
TRUE,
"Mutext Sample\0".as_ptr() as *const i8,
)
};
let _handle = Handle(handle);
if unsafe { GetLastError() } == ERROR_ALREADY_EXISTS {
println!("二つ目の起動");
return;
}
thread::sleep(Duration::from_secs(10));
println!("終了");
}
コンパイルして実行してみると排他制御できました。やったぜ。
windows-rs 版も書いておきます。2021/01/02 追記。
Cargo.toml
[package]
name = "multiboot_lock"
version = "0.1.0"
authors = ["benki"]
edition = "2021"
[dependencies.windows]
version = "0.30"
features = [
"alloc",
"Win32_Foundation",
"Win32_System_Threading",
"Win32_Foundation",
"Win32_Security"
]
main.rs
use std::ptr;
use std::thread;
use std::time::Duration;
use windows::{
core::{Error, Result},
Win32::{
Foundation::{CloseHandle, ERROR_ALREADY_EXISTS, HANDLE},
System::Threading::{CreateMutexW, ReleaseMutex},
},
};
struct Handle(HANDLE);
impl Drop for Handle {
fn drop(&mut self) {
if !self.0.is_invalid() {
println!("後始末");
unsafe {
ReleaseMutex(self.0);
CloseHandle(self.0);
}
}
}
}
fn main() -> Result<()> {
println!("Mutext の生成");
let handle = unsafe { CreateMutexW(ptr::null_mut(), true, "Mutext Sample").ok()? };
let _handle = Handle(handle);
if let Some(err) = Error::from_win32().win32_error() {
if err.eq(&ERROR_ALREADY_EXISTS) {
println!("二つ目の起動");
return Ok(());
}
}
thread::sleep(Duration::from_secs(10));
println!("終了");
Ok(())
}