|
1 | 1 | use anyhow::{anyhow, Result}; |
2 | 2 | use indexmap::IndexMap; |
3 | 3 | use windows::core::{Error, PCWSTR, PWSTR}; |
4 | | -use windows::Win32::Foundation::{SetLastError, BOOL, ERROR_SUCCESS, HANDLE, HWND, LPARAM}; |
| 4 | +use windows::Win32::Foundation::{ |
| 5 | + CloseHandle, SetLastError, BOOL, ERROR_ALREADY_EXISTS, ERROR_SUCCESS, HANDLE, HWND, LPARAM, |
| 6 | +}; |
5 | 7 | use windows::Win32::Graphics::Dwm::{DwmGetWindowAttribute, DWMWA_CLOAKED, DWM_CLOAKED_SHELL}; |
6 | 8 | use windows::Win32::System::Console::{AllocConsole, FreeConsole, GetConsoleWindow}; |
7 | 9 | use windows::Win32::System::LibraryLoader::GetModuleFileNameW; |
8 | 10 | use windows::Win32::System::Threading::{ |
9 | | - OpenProcess, QueryFullProcessImageNameW, PROCESS_NAME_WIN32, PROCESS_QUERY_INFORMATION, |
10 | | - PROCESS_VM_READ, |
| 11 | + CreateMutexW, OpenProcess, QueryFullProcessImageNameW, ReleaseMutex, PROCESS_NAME_WIN32, |
| 12 | + PROCESS_QUERY_INFORMATION, PROCESS_VM_READ, |
11 | 13 | }; |
12 | 14 | use windows::Win32::UI::Controls::STATE_SYSTEM_INVISIBLE; |
13 | 15 | use windows::Win32::UI::Input::KeyboardAndMouse::{RegisterHotKey, UnregisterHotKey, MOD_NOREPEAT}; |
@@ -321,3 +323,43 @@ impl CheckError for u16 { |
321 | 323 | pub fn to_wstring(value: &str) -> Vec<u16> { |
322 | 324 | value.encode_utf16().chain(Some(0)).collect::<Vec<u16>>() |
323 | 325 | } |
| 326 | + |
| 327 | +/// A struct representing one running instance. |
| 328 | +pub struct SingleInstance { |
| 329 | + handle: Option<HANDLE>, |
| 330 | +} |
| 331 | + |
| 332 | +unsafe impl Send for SingleInstance {} |
| 333 | +unsafe impl Sync for SingleInstance {} |
| 334 | + |
| 335 | +impl SingleInstance { |
| 336 | + /// Returns a new SingleInstance object. |
| 337 | + pub fn create(name: &str) -> Result<Self> { |
| 338 | + let name = to_wstring(name); |
| 339 | + let handle = unsafe { CreateMutexW(None, BOOL(1), PCWSTR(name.as_ptr())) } |
| 340 | + .map_err(|err| anyhow!("Fail to setup single instance, {err}"))?; |
| 341 | + let handle = |
| 342 | + if windows::core::Error::from_win32().code() == ERROR_ALREADY_EXISTS.to_hresult() { |
| 343 | + None |
| 344 | + } else { |
| 345 | + Some(handle) |
| 346 | + }; |
| 347 | + Ok(SingleInstance { handle }) |
| 348 | + } |
| 349 | + |
| 350 | + /// Returns whether this instance is single. |
| 351 | + pub fn is_single(&self) -> bool { |
| 352 | + self.handle.is_some() |
| 353 | + } |
| 354 | +} |
| 355 | + |
| 356 | +impl Drop for SingleInstance { |
| 357 | + fn drop(&mut self) { |
| 358 | + if let Some(handle) = self.handle.take() { |
| 359 | + unsafe { |
| 360 | + ReleaseMutex(handle); |
| 361 | + CloseHandle(handle); |
| 362 | + } |
| 363 | + } |
| 364 | + } |
| 365 | +} |
0 commit comments