diff --git a/RadeonResetBugFixService/ConsoleHelper.cs b/RadeonResetBugFixService/ConsoleHelper.cs deleted file mode 100644 index c9010a8..0000000 --- a/RadeonResetBugFixService/ConsoleHelper.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace RadeonResetBugFixService -{ - using System; - using System.Runtime.InteropServices; - - static class ConsoleHelper - { - private static class NativeMethods - { - [DllImport("kernel32.dll")] - public static extern IntPtr GetConsoleWindow(); - - [DllImport("user32.dll")] - public static extern bool IsWindowVisible(IntPtr hWnd); - } - - // Code taken from https://stackoverflow.com/a/53716169 - public static bool HaveVisibleConsole() - { - return NativeMethods.IsWindowVisible(NativeMethods.GetConsoleWindow()); - } - } -} diff --git a/RadeonResetBugFixService/EnvironmentHelper.cs b/RadeonResetBugFixService/EnvironmentHelper.cs new file mode 100644 index 0000000..32d69e3 --- /dev/null +++ b/RadeonResetBugFixService/EnvironmentHelper.cs @@ -0,0 +1,39 @@ +namespace RadeonResetBugFixService +{ + using System; + using System.Runtime.InteropServices; + using System.Security.Principal; + + static class EnvironmentHelper + { + private static class NativeMethods + { + [DllImport("kernel32.dll")] + public static extern IntPtr GetConsoleWindow(); + + [DllImport("user32.dll")] + public static extern bool IsWindowVisible(IntPtr hWnd); + } + + private static Version VistaVersion { get; } = new Version(6, 0); + + private static Version Windows8Version { get; } = new Version(6, 2); + + // Code taken from https://stackoverflow.com/a/53716169 + public static bool IsConsoleVisibleOnWindows() => NativeMethods.IsWindowVisible(NativeMethods.GetConsoleWindow()); + + private static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + // Code taken from https://stackoverflow.com/a/2679654 + public static bool HasAdministratorPrivileges() + { + WindowsIdentity id = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new WindowsPrincipal(id); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + + public static bool IsWindows8OrNewer() => IsWindows() && Environment.OSVersion.Version >= Windows8Version; + + public static bool IsVistaOrNewer() => IsWindows() && Environment.OSVersion.Version >= VistaVersion; + } +} diff --git a/RadeonResetBugFixService/Program.cs b/RadeonResetBugFixService/Program.cs index 79f6adb..cb1ed5a 100644 --- a/RadeonResetBugFixService/Program.cs +++ b/RadeonResetBugFixService/Program.cs @@ -1,8 +1,6 @@ namespace RadeonResetBugFixService { using System; - using System.Runtime.InteropServices; - using System.Security.Principal; using System.ServiceProcess; using ThirdParty.ServiceHelpers; @@ -18,15 +16,15 @@ throw new ArgumentNullException(nameof(args)); } - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (!EnvironmentHelper.IsVistaOrNewer()) { - Console.Error.WriteLine("This program only runs on Windows"); + Console.Error.WriteLine("This program only runs on Windows Vista or newer"); return -1; } - if (ConsoleHelper.HaveVisibleConsole()) + if (EnvironmentHelper.IsConsoleVisibleOnWindows()) { - if (!HasAdministratorPrivileges()) + if (!EnvironmentHelper.HasAdministratorPrivileges()) { Console.Error.WriteLine("Access Denied."); Console.Error.WriteLine("Administrator permissions are needed to use this tool."); @@ -43,14 +41,10 @@ } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "Windows service initialization")] private static int MainService() { - ServiceBase[] ServicesToRun; - ServicesToRun = new ServiceBase[] - { - new RadeonResetBugFixService() - }; - ServiceBase.Run(ServicesToRun); + ServiceBase.Run(new RadeonResetBugFixService()); return 0; } @@ -142,13 +136,5 @@ { new MainHandler().HandleShutdown("Program.DoShutdown"); } - - // Code taken from https://stackoverflow.com/a/2679654 - private static bool HasAdministratorPrivileges() - { - WindowsIdentity id = WindowsIdentity.GetCurrent(); - WindowsPrincipal principal = new WindowsPrincipal(id); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } } } diff --git a/RadeonResetBugFixService/Properties/app.manifest b/RadeonResetBugFixService/Properties/app.manifest new file mode 100644 index 0000000..9abde23 --- /dev/null +++ b/RadeonResetBugFixService/Properties/app.manifest @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RadeonResetBugFixService/RadeonResetBugFixService.cs b/RadeonResetBugFixService/RadeonResetBugFixService.cs index 1893de0..9062787 100644 --- a/RadeonResetBugFixService/RadeonResetBugFixService.cs +++ b/RadeonResetBugFixService/RadeonResetBugFixService.cs @@ -92,12 +92,15 @@ "ServiceBase.OnCustomCommand", (string reason) => { - this.Handler.HandleLog($"Custom command: {command}"); - if (command == SERVICE_CONTROL_PRESHUTDOWN) { + this.Handler.HandleLog($"Custom command: preshutdown"); this.CallStop(); } + else + { + this.Handler.HandleLog($"Unknown custom command: {command}"); + } }); } diff --git a/RadeonResetBugFixService/RadeonResetBugFixService.csproj b/RadeonResetBugFixService/RadeonResetBugFixService.csproj index 40855ee..b6e6e21 100644 --- a/RadeonResetBugFixService/RadeonResetBugFixService.csproj +++ b/RadeonResetBugFixService/RadeonResetBugFixService.csproj @@ -44,6 +44,9 @@ + + Properties\app.manifest + @@ -58,7 +61,7 @@ - + @@ -106,6 +109,7 @@ + diff --git a/RadeonResetBugFixService/RegistryHelper.cs b/RadeonResetBugFixService/RegistryHelper.cs index 69867d1..820d9cb 100644 --- a/RadeonResetBugFixService/RegistryHelper.cs +++ b/RadeonResetBugFixService/RegistryHelper.cs @@ -19,15 +19,21 @@ } } - private static RegistryValuePath PreshutdownOrderPath = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control", "PreshutdownOrder"); + private static string BasicDisplayServiceName { get; } = ( + EnvironmentHelper.IsWindows8OrNewer() + ? "BasicDisplay" + : "vga" + ); - private static RegistryValuePath WaitToKillServiceTimeoutPath = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control", "WaitToKillServiceTimeout"); + private static RegistryValuePath PreshutdownOrderPath { get; } = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control", "PreshutdownOrder"); - private static RegistryValuePath FastRebootPath = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Power", "HiberbootEnabled"); + private static RegistryValuePath WaitToKillServiceTimeoutPath { get; } = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control", "WaitToKillServiceTimeout"); - private static RegistryValuePath NoInteractiveServicesPath = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows", "NoInteractiveServices"); + private static RegistryValuePath FastRebootPath { get; } = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Power", "HiberbootEnabled"); - private static RegistryValuePath BasicDisplayStartTypePath = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BasicDisplay", "Start"); + private static RegistryValuePath NoInteractiveServicesPath { get; } = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows", "NoInteractiveServices"); + + private static RegistryValuePath BasicDisplayStartTypePath { get; } = new RegistryValuePath(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\" + BasicDisplayServiceName, "Start"); private static T GetValue(RegistryValuePath path, T defaultValue = default) => (T)Registry.GetValue(path.KeyName, path.ValueName, defaultValue);