From f4ef2a2c9a5cffb68ac5e9ca53f1a1654bb773af Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 7 Sep 2018 07:46:36 +1200 Subject: [PATCH 1/3] Tidying --- Mamesaver/GamePlayManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mamesaver/GamePlayManager.cs b/Mamesaver/GamePlayManager.cs index 79a7c4f..e60b7af 100644 --- a/Mamesaver/GamePlayManager.cs +++ b/Mamesaver/GamePlayManager.cs @@ -139,7 +139,7 @@ private void PreviousGame() } /// - /// Deselects a game, saving configuration and playing the next game + /// Deselects a game, saving configuration and playing the next game. /// private void DeselectGame(Game game) { From c9c42a44d6ba77a0990dd800611860990b5c7b3c Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 7 Sep 2018 07:48:01 +1200 Subject: [PATCH 2/3] #29 prevented sleep timer created if no power saving enabled --- Mamesaver/Power/PowerManager.cs | 59 +++++++++++++++++++++---------- Mamesaver/Windows/PowerInterop.cs | 19 ++++++---- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Mamesaver/Power/PowerManager.cs b/Mamesaver/Power/PowerManager.cs index 374e48b..71a0e51 100644 --- a/Mamesaver/Power/PowerManager.cs +++ b/Mamesaver/Power/PowerManager.cs @@ -32,7 +32,7 @@ public class PowerManager : IDisposable /// Time before a event is published, based on the user's power management /// configuration. /// - private TimeSpan _sleepTimeout; + private TimeSpan? _sleepTimeout; /// /// Current power source type. @@ -72,24 +72,43 @@ public void Initialise() // Identify policy for selected power type _sleepTimeout = GetSleepTimeout(powerType.Value); - Log.Information("Connected to {powerType} power; sleeping after {min} minutes", - powerType.Value.ToString(), _sleepTimeout.TotalMinutes); - - // Create a timer which fires once when the display or computer should go to sleep - _sleepTimer = new Timer { Interval = (int)_sleepTimeout.TotalMilliseconds, AutoReset = false }; - - _sleepTimer.Elapsed += SleepTimerTick; - _sleepTimer.Start(); + if (_sleepTimeout == null) + { + Log.Information("Connected to {powerType} power; no sleep configured", powerType.Value.ToString()); + } + else + { + // Create a timer which fires once when the display or computer should go to sleep + Log.Information("Connected to {powerType} power; sleeping after {min} minutes", powerType.Value.ToString(), _sleepTimeout.Value.TotalMinutes); + InitSleepTimer(); + } // Receive notifications for power state changes so the timer can be updated _eventWatcher.Initialise(); _eventWatcher.PowerStateChanged += PowerStateChanged; } + /// + /// Either creates or updates the sleep timer. + /// + private void InitSleepTimer() + { + if (_sleepTimeout == null) throw new InvalidOperationException("Can't create a timer with no timeout specified"); + + if (_sleepTimer == null) + { + _sleepTimer = new Timer { AutoReset = false }; + _sleepTimer.Elapsed += SleepTimerTick; + } + + _sleepTimer.Interval = (int)_sleepTimeout.Value.TotalMilliseconds; + _sleepTimer.Start(); + } + /// /// Returns the lowest of screen and PC sleep settings for a given power type. /// - private static TimeSpan GetSleepTimeout(PowerType powerType) + private static TimeSpan? GetSleepTimeout(PowerType powerType) { var powerPolicy = PowerInterop.GetPowerPolicy(powerType); return new[] { powerPolicy.VideoTimeout, powerPolicy.IdleTimeout }.Min(); @@ -119,16 +138,20 @@ private void PowerStateChanged(object sender, EventArgs args) if (_currentPowerType == powerType) return; _currentPowerType = powerType.Value; + _sleepTimer?.Stop(); + // Identify policy for selected power type _sleepTimeout = GetSleepTimeout(powerType.Value); - Log.Information("Power changed to {powerType} power; sleeping after {min} minutes", - powerType.Value.ToString(), _sleepTimeout.TotalMinutes); - - // Update sleep timer on power state change due to different sleep configurations - _sleepTimer.Interval = (int)_sleepTimeout.TotalMilliseconds; - - _sleepTimer.Stop(); - _sleepTimer.Start(); + if (_sleepTimeout == null) + { + Log.Information("Power changed to {powerType} power; no sleep configured", powerType.Value.ToString()); + } + else + { + // Update sleep timer on power state change due to different sleep configurations + Log.Information("Power changed to {powerType} power; sleeping after {min} minutes", powerType.Value.ToString(), _sleepTimeout.Value.TotalMinutes); + InitSleepTimer(); + } } /// diff --git a/Mamesaver/Windows/PowerInterop.cs b/Mamesaver/Windows/PowerInterop.cs index af23e4f..7eb333f 100644 --- a/Mamesaver/Windows/PowerInterop.cs +++ b/Mamesaver/Windows/PowerInterop.cs @@ -37,10 +37,10 @@ public static PowerPolicy GetPowerPolicy(PowerType powerType) { IdleTimeout = userPolicy.IdleTimeoutAc == 0 || userPolicy.IdleAc.Action == POWER_ACTION.PowerActionNone - ? TimeSpan.MaxValue + ? (TimeSpan?)null : TimeSpan.FromSeconds(userPolicy.IdleTimeoutAc), VideoTimeout = userPolicy.VideoTimeoutAc == 0 - ? TimeSpan.MaxValue + ? (TimeSpan?)null : TimeSpan.FromSeconds(userPolicy.VideoTimeoutAc) }; case PowerType.DC: @@ -48,10 +48,10 @@ public static PowerPolicy GetPowerPolicy(PowerType powerType) { IdleTimeout = userPolicy.IdleTimeoutDc == 0 || userPolicy.IdleDc.Action == POWER_ACTION.PowerActionNone - ? TimeSpan.MaxValue + ? (TimeSpan?)null : TimeSpan.FromSeconds(userPolicy.IdleTimeoutDc), VideoTimeout = userPolicy.VideoTimeoutDc == 0 - ? TimeSpan.MaxValue + ? (TimeSpan?)null : TimeSpan.FromSeconds(userPolicy.VideoTimeoutDc) }; default: @@ -68,7 +68,14 @@ public enum PowerType public class PowerPolicy { - public TimeSpan VideoTimeout { get; set; } - public TimeSpan IdleTimeout { get; set; } + /// + /// Timeout for screen to go to sleep, or null if no sleep is specified. + /// + public TimeSpan? VideoTimeout { get; set; } + + /// + /// Timeout for PC to go to sleep, or null if no sleep is specified. + /// + public TimeSpan? IdleTimeout { get; set; } } } \ No newline at end of file From ca5deae5ab42a8caea1fd916dfdaf0ea862bc420 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 7 Sep 2018 08:40:20 +1200 Subject: [PATCH 3/3] Fixed issues identified by VS code analysis --- Mamesaver/BlankScreen.cs | 18 ++++++++++- Mamesaver/CaptureScreen.cs | 2 +- Mamesaver/GamePlayManager.cs | 6 ++-- Mamesaver/MameScreen.cs | 12 +++---- Mamesaver/Power/PowerEventWatcher.cs | 6 ++-- Mamesaver/Power/PowerManager.cs | 4 +-- Mamesaver/Windows/PlatformInvokeGDI32.cs | 22 ++++++------- Mamesaver/Windows/PlatformInvokeUSER32.cs | 38 +++++++++++------------ Mamesaver/Windows/UserActivityHook.cs | 13 +++++--- 9 files changed, 68 insertions(+), 53 deletions(-) diff --git a/Mamesaver/BlankScreen.cs b/Mamesaver/BlankScreen.cs index 69dea49..52cddf6 100644 --- a/Mamesaver/BlankScreen.cs +++ b/Mamesaver/BlankScreen.cs @@ -10,7 +10,7 @@ namespace Mamesaver { - internal class BlankScreen + internal class BlankScreen : IDisposable { private readonly PowerManager _powerManager; public BackgroundForm BackgroundForm { get; } @@ -96,5 +96,21 @@ private void ReleaseDeviceContext() Log.Error(ex, "Error releasing device context for {screen}", Screen.DeviceName); } } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; + + _powerManager?.Dispose(); + BackgroundForm?.Dispose(); + } + + ~BlankScreen() => Dispose(false); } } \ No newline at end of file diff --git a/Mamesaver/CaptureScreen.cs b/Mamesaver/CaptureScreen.cs index 5dbe190..b20d39f 100644 --- a/Mamesaver/CaptureScreen.cs +++ b/Mamesaver/CaptureScreen.cs @@ -33,7 +33,7 @@ public void Dispose() GC.SuppressFinalize(this); } - public virtual void Dispose(bool disposing) => ReleaseUnmanagedResources(); + protected virtual void Dispose(bool disposing) => ReleaseUnmanagedResources(); ~CaptureScreen() => Dispose(false); private void ReleaseUnmanagedResources() diff --git a/Mamesaver/GamePlayManager.cs b/Mamesaver/GamePlayManager.cs index e60b7af..d8c3e81 100644 --- a/Mamesaver/GamePlayManager.cs +++ b/Mamesaver/GamePlayManager.cs @@ -26,9 +26,9 @@ internal class GamePlayManager : IDisposable private readonly PowerManager _powerManager; private readonly MameInvoker _invoker; - public delegate void PlayGameEventHandler(object sender, EventArgs args); - public delegate void StartGameEventHandler(object sender, EventArgs args); - public delegate void GameStartedEventHandler(object sender, EventArgs args); + public delegate void PlayGameEventHandler(object sender, EventArgs e); + public delegate void StartGameEventHandler(object sender, EventArgs e); + public delegate void GameStartedEventHandler(object sender, EventArgs e); /// /// Game has been started by MAME. diff --git a/Mamesaver/MameScreen.cs b/Mamesaver/MameScreen.cs index 10d1541..140e03d 100644 --- a/Mamesaver/MameScreen.cs +++ b/Mamesaver/MameScreen.cs @@ -12,7 +12,7 @@ namespace Mamesaver /// A screen that will launch MAME with a random game from the list. If configured, this screen also handles hotkey events which /// affect the MAME process. /// - internal class MameScreen : BlankScreen, IDisposable + internal class MameScreen : BlankScreen { private readonly Settings _settings; private readonly GamePlayManager _gamePlayManager; @@ -163,8 +163,10 @@ private void GameTimerTick(object sender, EventArgs e) /// Stop the timer, set cancelled flag, close any current process and close the background form. /// Once this has all been done, the application should end. /// - public virtual void Dispose(bool disposing) + protected override void Dispose(bool disposing) { + base.Dispose(disposing); + if (!disposing || !_initialised) return; Log.Information("Closing primary MAME screen {screen}", Screen.DeviceName); @@ -187,12 +189,6 @@ private void DisposeTimers() _gameTimer = _splashTimer = null; } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - ~MameScreen() => Dispose(false); } } \ No newline at end of file diff --git a/Mamesaver/Power/PowerEventWatcher.cs b/Mamesaver/Power/PowerEventWatcher.cs index 1d06f38..3adfd34 100644 --- a/Mamesaver/Power/PowerEventWatcher.cs +++ b/Mamesaver/Power/PowerEventWatcher.cs @@ -8,7 +8,7 @@ namespace Mamesaver.Power /// Listens for power source change events, firing a event /// if received. /// - public class PowerEventWatcher + public class PowerEventWatcher : IDisposable { /// /// Value of event corresponding to a power state change. @@ -21,7 +21,7 @@ public class PowerEventWatcher private ManagementEventWatcher _managementEventWatcher; public event PowerEventHandler PowerStateChanged; - public delegate void PowerEventHandler(object sender, EventArgs args); + public delegate void PowerEventHandler(object sender, EventArgs e); /// /// Initialises the power event watcher to fire @@ -51,7 +51,7 @@ private void PowerEventArrived(object sender, EventArrivedEventArgs args) } } - public virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) { if (!disposing) return; diff --git a/Mamesaver/Power/PowerManager.cs b/Mamesaver/Power/PowerManager.cs index 71a0e51..3c25e05 100644 --- a/Mamesaver/Power/PowerManager.cs +++ b/Mamesaver/Power/PowerManager.cs @@ -21,7 +21,7 @@ public class PowerManager : IDisposable private readonly PowerEventWatcher _eventWatcher; private Timer _sleepTimer; - public delegate void SleepTriggerManager(object sender, EventArgs args); + public delegate void SleepTriggerManager(object sender, EventArgs e); /// /// Fired when the screensaver should turn the display to sleep. @@ -165,7 +165,7 @@ public void Dispose() GC.SuppressFinalize(this); } - public virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) { if (!disposing) return; _sleepTimer?.Dispose(); diff --git a/Mamesaver/Windows/PlatformInvokeGDI32.cs b/Mamesaver/Windows/PlatformInvokeGDI32.cs index 10aba38..bb0b2e1 100644 --- a/Mamesaver/Windows/PlatformInvokeGDI32.cs +++ b/Mamesaver/Windows/PlatformInvokeGDI32.cs @@ -4,38 +4,38 @@ namespace Mamesaver.Windows { - public class PlatformInvokeGdi32 + internal class PlatformInvokeGdi32 { - public const int SRCOPY = 13369376; + internal const int SRCOPY = 13369376; [DllImport("gdi32.dll", EntryPoint = "DeleteDC")] - public static extern IntPtr DeleteDC(IntPtr hDc); + internal static extern IntPtr DeleteDC(IntPtr hDc); [DllImport("gdi32.dll", EntryPoint = "DeleteObject")] - public static extern IntPtr DeleteObject(IntPtr hDc); + internal static extern IntPtr DeleteObject(IntPtr hDc); [DllImport("gdi32.dll", EntryPoint = "BitBlt")] - public static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int rasterOp); + internal static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int rasterOp); [DllImport("gdi32.dll", EntryPoint = "StretchBlt")] - public static extern bool StretchBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int wSrc, int hSrc, int RasterOp); + internal static extern bool StretchBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int wSrc, int hSrc, int RasterOp); [DllImport("gdi32.dll")] - public static extern IntPtr CreateCompatibleDC(IntPtr hdc); + internal static extern IntPtr CreateCompatibleDC(IntPtr hdc); [DllImport("gdi32.dll")] - public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight); + internal static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight); [DllImport("gdi32.dll", EntryPoint = "SelectObject")] - public static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp); + internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp); [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] - public static extern int GetDeviceCaps(IntPtr hDC, int nIndex); + internal static extern int GetDeviceCaps(IntPtr hDC, int nIndex); /// /// DeviceCap - Device capabilities /// - public enum DeviceCap + internal enum DeviceCap { /// /// Logical pixels inch in X diff --git a/Mamesaver/Windows/PlatformInvokeUSER32.cs b/Mamesaver/Windows/PlatformInvokeUSER32.cs index 4d94ac3..d539329 100644 --- a/Mamesaver/Windows/PlatformInvokeUSER32.cs +++ b/Mamesaver/Windows/PlatformInvokeUSER32.cs @@ -4,51 +4,51 @@ namespace Mamesaver.Windows { - public class PlatformInvokeUser32 + internal class PlatformInvokeUser32 { - public const int SM_CXSCREEN = 0; - public const int SM_CYSCREEN = 1; - public const int SW_MINIMIZE = 6; + internal const int SM_CXSCREEN = 0; + internal const int SM_CYSCREEN = 1; + internal const int SW_MINIMIZE = 6; [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam); + internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam); [DllImport("user32.dll")] - public static extern void SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags); + internal static extern void SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags); [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")] - public static extern IntPtr GetDesktopWindow(); + internal static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", EntryPoint = "GetDC")] - public static extern IntPtr GetDC(IntPtr ptr); + internal static extern IntPtr GetDC(IntPtr ptr); [DllImport("user32.dll", EntryPoint = "GetSystemMetrics")] - public static extern int GetSystemMetrics(int abc); + internal static extern int GetSystemMetrics(int abc); [DllImport("user32.dll", EntryPoint = "GetWindowDC")] - public static extern IntPtr GetWindowDC(Int32 ptr); + internal static extern IntPtr GetWindowDC(Int32 ptr); [DllImport("user32.dll", EntryPoint = "ReleaseDC")] - public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC); + internal static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); + internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); [StructLayout(LayoutKind.Sequential)] - public struct RECT + internal struct RECT { - public int Left; // x position of upper-left corner - public int Top; // y position of upper-left corner - public int Right; // x position of lower-right corner - public int Bottom; // y position of lower-right corner + internal int Left; // x position of upper-left corner + internal int Top; // y position of upper-left corner + internal int Right; // x position of lower-right corner + internal int Bottom; // y position of lower-right corner } [DllImport("user32.dll")] - public static extern bool SetProcessDPIAware(); + internal static extern bool SetProcessDPIAware(); } } diff --git a/Mamesaver/Windows/UserActivityHook.cs b/Mamesaver/Windows/UserActivityHook.cs index dda76f1..9e1a6b0 100644 --- a/Mamesaver/Windows/UserActivityHook.cs +++ b/Mamesaver/Windows/UserActivityHook.cs @@ -480,18 +480,21 @@ public UserActivityHook(bool InstallMouseHook, bool InstallKeyboardHook) } public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) { //uninstall hooks and do not throw exceptions - Stop(true, true, false); + Stop(true, true, false); } /// /// Destruction. /// - ~UserActivityHook() - { - Dispose(); - } + ~UserActivityHook() => Dispose(false); /// /// Occurs when the user moves the mouse, presses any mouse button or scrolls the wheel