diff --git a/Screensaver.cs b/Screensaver.cs index a1bf929..951b80f 100644 --- a/Screensaver.cs +++ b/Screensaver.cs @@ -23,6 +23,8 @@ using System.Runtime.InteropServices; using System.Threading; using System.Diagnostics; using System.Collections.Generic; +using System.Security.AccessControl; +using System.Security.Principal; namespace Screensavers { @@ -291,7 +293,7 @@ namespace Screensavers switch (screensaverMode) { case ScreensaverMode.Windowed: - RunWindowed(); + RunWithSingleInstanceMutex(screensaverMode); break; case ScreensaverMode.Settings: ShowSettingsDialog(); @@ -304,7 +306,7 @@ namespace Screensavers if (!closeOnKeyboardInputOverride) closeOnKeyboardInput = true; - RunNormal(); + RunWithSingleInstanceMutex(screensaverMode); break; case ScreensaverMode.Preview: RunPreview(); @@ -504,6 +506,81 @@ namespace Screensavers set { windowTitle = value; } } + private void RunWithSingleInstanceMutex(ScreensaverMode screensaverMode) + { + // From: https://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c/229567 + // get application GUID as defined in AssemblyInfo.cs + string appGuid = + ((GuidAttribute)System.Reflection.Assembly.GetExecutingAssembly(). + GetCustomAttributes(typeof(GuidAttribute), false). + GetValue(0)).Value.ToString(); + + // unique id for global mutex - Global prefix means it is global to the machine + string mutexId = string.Format("Global\\{{{0}}}", appGuid); + + // Need a place to store a return value in Mutex() constructor call + bool createdNew; + + // edited by Jeremy Wiebe to add example of setting up security for multi-user usage + // edited by 'Marc' to work also on localized systems (don't use just "Everyone") + var allowEveryoneRule = + new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid + , null) + , MutexRights.FullControl + , AccessControlType.Allow + ); + var securitySettings = new MutexSecurity(); + securitySettings.AddAccessRule(allowEveryoneRule); + + // edited by MasonGZhwiti to prevent race condition on security settings via VanNguyen + using (var mutex = new Mutex(false, mutexId, out createdNew, securitySettings)) + { + // edited by acidzombie24 + var hasHandle = false; + try + { + try + { + // note, you may want to time out here instead of waiting forever + // edited by acidzombie24 + // mutex.WaitOne(Timeout.Infinite, false); + hasHandle = mutex.WaitOne(5000, false); + if (hasHandle == false) + throw new TimeoutException("Timeout waiting for exclusive access"); + } + catch (AbandonedMutexException) + { + // Log the fact that the mutex was abandoned in another process, + // it will still get acquired + hasHandle = true; + } + + // Actuall Run. + switch (screensaverMode) + { + case ScreensaverMode.Windowed: + RunWindowed(); + break; + case ScreensaverMode.Settings: + ShowSettingsDialog(); + break; + case ScreensaverMode.Normal: + RunNormal(); + break; + case ScreensaverMode.Preview: + RunPreview(); + break; + } + } + finally + { + // edited by acidzombie24, added if statement + if (hasHandle) + mutex.ReleaseMutex(); + } + } + } + private void RunNormal() { Cursor.Hide();