unit PM.SingleInstance; { Single-instance guard. AcquireOrSignal: - First instance: creates a named mutex and returns True. Caller proceeds. - Subsequent instance: detects the mutex, broadcasts WM_PMSHOW so the running instance restores from tray, returns False. Caller exits. WM_PMSHOW is a RegisterWindowMessage('PMServer_ShowExisting') — system- unique, all processes that register the same string get the same ID. PM.Bridge listens for it on its message-only window. } interface uses Winapi.Windows, Winapi.Messages; const // Mutex name lives in the Local\ namespace → per-user-session, so a // second user on the same machine (RDP, Switch User) can still launch // their own instance. The Global\ namespace would block them. PMSERVER_MUTEX_NAME = 'Local\PMServer.SingleInstance.Mutex'; // System-wide unique message ID, computed once. Bridge + .dpr both call // this to get the same UINT. function WM_PMShowMessage: UINT; // Try to become the single instance. True = we are first; False = another // instance was already running (we have signalled it and the caller must // exit immediately). function AcquireOrSignal: Boolean; implementation var _Mutex: THandle = 0; _WmShow: UINT = 0; function WM_PMShowMessage: UINT; begin if _WmShow = 0 then _WmShow := RegisterWindowMessage('PMServer_ShowExisting'); Result := _WmShow; end; function AcquireOrSignal: Boolean; var LErr: DWORD; begin _Mutex := CreateMutex(nil, True, PMSERVER_MUTEX_NAME); LErr := GetLastError; if (_Mutex <> 0) and (LErr <> ERROR_ALREADY_EXISTS) then begin // We are the first instance. Keep the mutex alive for the process // lifetime — Windows releases it automatically on exit. Result := True; Exit; end; // Another instance is already running. Close our handle (it isn't ours) // and broadcast the show-message to all top-level windows. The running // bridge picks it up on its message-only window. if _Mutex <> 0 then begin CloseHandle(_Mutex); _Mutex := 0; end; PostMessage(HWND_BROADCAST, WM_PMShowMessage, 0, 0); Result := False; end; end.