diff --git a/RadeonResetBugFix.sln b/RadeonResetBugFix.sln
new file mode 100644
index 0000000..e09a1e2
--- /dev/null
+++ b/RadeonResetBugFix.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29519.87
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonResetBugFixService", "RadeonResetBugFixService\RadeonResetBugFixService.csproj", "{1B9A6DE9-69F9-48B2-B70D-632E5766404A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1B9A6DE9-69F9-48B2-B70D-632E5766404A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1B9A6DE9-69F9-48B2-B70D-632E5766404A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B9A6DE9-69F9-48B2-B70D-632E5766404A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1B9A6DE9-69F9-48B2-B70D-632E5766404A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {67C6E2F8-1519-4E55-9C93-1EAD4050026F}
+ EndGlobalSection
+EndGlobal
diff --git a/RadeonResetBugFixService/App.config b/RadeonResetBugFixService/App.config
new file mode 100644
index 0000000..56efbc7
--- /dev/null
+++ b/RadeonResetBugFixService/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RadeonResetBugFixService/Contracts/DeviceInfo.cs b/RadeonResetBugFixService/Contracts/DeviceInfo.cs
new file mode 100644
index 0000000..7fb7ed1
--- /dev/null
+++ b/RadeonResetBugFixService/Contracts/DeviceInfo.cs
@@ -0,0 +1,25 @@
+namespace RadeonResetBugFixService.Contracts
+{
+ using System;
+
+ class DeviceInfo
+ {
+ public Guid ClassGuid { get; set; }
+
+ public string ClassName { get; set; }
+
+ public string DeviceId { get; set; }
+
+ public long? ErrorCode { get; set; }
+
+ public bool IsDisabled => this.ErrorCode == 22;
+
+ public bool IsPresent { get; set; }
+
+ public string Manufacturer { get; set; }
+
+ public string Name { get; set; }
+
+ public string Service { get; set; }
+ }
+}
diff --git a/RadeonResetBugFixService/Contracts/ILogger.cs b/RadeonResetBugFixService/Contracts/ILogger.cs
new file mode 100644
index 0000000..e1d9885
--- /dev/null
+++ b/RadeonResetBugFixService/Contracts/ILogger.cs
@@ -0,0 +1,10 @@
+namespace RadeonResetBugFixService.Contracts
+{
+ using System;
+
+ interface ILogger : IDisposable
+ {
+ void Log(string message);
+ void LogError(string message);
+ }
+}
diff --git a/RadeonResetBugFixService/Devices/DeviceHelper.cs b/RadeonResetBugFixService/Devices/DeviceHelper.cs
new file mode 100644
index 0000000..9ae2bac
--- /dev/null
+++ b/RadeonResetBugFixService/Devices/DeviceHelper.cs
@@ -0,0 +1,83 @@
+namespace RadeonResetBugFixService.Devices
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Management;
+ using Contracts;
+
+ class DeviceHelper
+ {
+ private static T GetProperty(PropertyDataCollection properties, string key)
+ {
+ try
+ {
+ return (T)properties[key].Value;
+ }
+ catch (Exception)
+ {
+ return default;
+ }
+ }
+
+ private static Guid GuidTryParse(string input)
+ {
+ Guid.TryParse(input, out var result);
+ return result;
+ }
+
+ private static DeviceInfo ConvertDeviceInfo(PropertyDataCollection deviceProperties)
+ {
+ return new DeviceInfo
+ {
+ ClassGuid = GuidTryParse(GetProperty(deviceProperties, "ClassGuid")),
+ ClassName = GetProperty(deviceProperties, "PNPClass") ?? string.Empty,
+ DeviceId = GetProperty(deviceProperties, "PNPDeviceId") ?? string.Empty,
+ ErrorCode = GetProperty(deviceProperties, "ConfigManagerErrorCode"),
+ IsPresent = GetProperty(deviceProperties, "Present"),
+ Manufacturer = GetProperty(deviceProperties, "Manufacturer") ?? string.Empty,
+ Name = GetProperty(deviceProperties, "Name") ?? string.Empty,
+ Service = GetProperty(deviceProperties, "Service") ?? string.Empty,
+ };
+ }
+
+ public static IEnumerable GetDevices()
+ {
+ ManagementPath path = new ManagementPath
+ {
+ Server = ".",
+ NamespacePath = @"root\CIMV2",
+ RelativePath = @"Win32_PnPentity",
+ };
+
+ using (var devs = new ManagementClass(new ManagementScope(path), path, new ObjectGetOptions(null, TimeSpan.FromMinutes(1), false)))
+ {
+ ManagementObjectCollection moc = devs.GetInstances();
+ foreach (ManagementObject mo in moc)
+ {
+ /*Console.WriteLine("===================================");
+ Console.WriteLine("New device: " + mo.Path.Path);
+ PropertyDataCollection devsProperties = mo.Properties;
+ foreach (PropertyData devProperty in devsProperties)
+ {
+ if (devProperty.Type != CimType.DateTime)
+ {
+ Console.WriteLine("Property = {0}\tValue = {1}\tType={2}", devProperty.Name, devProperty.Value, devProperty.Value?.GetType()?.Name);
+ }
+ }*/
+
+ yield return ConvertDeviceInfo(mo.Properties);
+ }
+ }
+ }
+
+ public static void DisableDevice(DeviceInfo deviceInfo)
+ {
+ ThirdParty.DisableDevice.DeviceHelper.SetDeviceEnabled(deviceInfo.ClassGuid, deviceInfo.DeviceId, false);
+ }
+
+ public static void EnableDevice(DeviceInfo deviceInfo)
+ {
+ ThirdParty.DisableDevice.DeviceHelper.SetDeviceEnabled(deviceInfo.ClassGuid, deviceInfo.DeviceId, true);
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/Devices/KnownDevices.cs b/RadeonResetBugFixService/Devices/KnownDevices.cs
new file mode 100644
index 0000000..814a933
--- /dev/null
+++ b/RadeonResetBugFixService/Devices/KnownDevices.cs
@@ -0,0 +1,18 @@
+namespace RadeonResetBugFixService.Devices
+{
+ using Contracts;
+
+ static class KnownDevices
+ {
+ public static bool IsAmdVideo(DeviceInfo device)
+ {
+ return (device.Manufacturer.ToLowerInvariant() == "amd" || device.Manufacturer.ToLowerInvariant().Contains("advanced micro devices")) &&
+ (device.Service.ToLowerInvariant() == "hdaudbus" || device.ClassName.ToLowerInvariant() == "display");
+ }
+
+ public static bool IsVirtualVideo(DeviceInfo device)
+ {
+ return device.Service.ToLowerInvariant() == "hypervideo";
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/Logging/FileLogger.cs b/RadeonResetBugFixService/Logging/FileLogger.cs
new file mode 100644
index 0000000..330cebe
--- /dev/null
+++ b/RadeonResetBugFixService/Logging/FileLogger.cs
@@ -0,0 +1,26 @@
+namespace RadeonResetBugFixService.Logging
+{
+ using System;
+ using System.IO;
+ using Contracts;
+
+ class FileLogger : ILogger
+ {
+ private string Filename { get; }
+
+ public FileLogger(string filename)
+ {
+ this.Filename = filename;
+ }
+
+ private void LogString(string message) => File.AppendAllLines(this.Filename, new[] { $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {message}" });
+
+ void ILogger.Log(string message) => LogString(message);
+
+ void ILogger.LogError(string message) => LogString($"Error: {message}");
+
+ void IDisposable.Dispose()
+ {
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/Logging/TaskLoggerWrapper.cs b/RadeonResetBugFixService/Logging/TaskLoggerWrapper.cs
new file mode 100644
index 0000000..323a393
--- /dev/null
+++ b/RadeonResetBugFixService/Logging/TaskLoggerWrapper.cs
@@ -0,0 +1,26 @@
+namespace RadeonResetBugFixService.Logging
+{
+ using System;
+ using Contracts;
+
+ class TaskLoggerWrapper : ILogger
+ {
+ private ILogger InnerLogger { get; }
+
+ private string Prefix { get; }
+
+ public TaskLoggerWrapper(ILogger innerLogger, string taskName)
+ {
+ this.InnerLogger = innerLogger;
+ this.Prefix = $"[{taskName}]";
+
+ innerLogger.Log($"{this.Prefix} begin");
+ }
+
+ void ILogger.Log(string message) => this.InnerLogger.Log($"{this.Prefix} {message}");
+
+ void ILogger.LogError(string message) => this.InnerLogger.LogError($"{this.Prefix} {message}");
+
+ void IDisposable.Dispose() => this.InnerLogger.Log($"{this.Prefix} end");
+ }
+}
diff --git a/RadeonResetBugFixService/MainHandler.cs b/RadeonResetBugFixService/MainHandler.cs
new file mode 100644
index 0000000..3d810d5
--- /dev/null
+++ b/RadeonResetBugFixService/MainHandler.cs
@@ -0,0 +1,66 @@
+namespace RadeonResetBugFixService
+{
+ using System;
+ using System.IO;
+ using System.Reflection;
+ using Contracts;
+ using Logging;
+ using Tasks;
+
+ class MainHandler
+ {
+ private string LogFilename { get; }
+
+ private object Mutex = new object();
+
+ public MainHandler()
+ {
+ var date = DateTime.Now;
+ this.LogFilename = Path.Combine(
+ Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
+ "logs",
+ $"radeonfix_{date:yyyyMMdd}_{date:HHmmss}.log");
+ }
+
+ public void HandleStartup()
+ {
+ using (var fileLogger = new FileLogger(this.LogFilename))
+ {
+ using (ILogger logger = new TaskLoggerWrapper(fileLogger, "Startup"))
+ {
+ lock (this.Mutex)
+ {
+ TasksProcessor.ProcessTasks(
+ logger,
+ new ITask[]
+ {
+ new DisableVirtualVideoTask(),
+ new EnableAmdVideoTask(),
+ });
+ }
+ }
+ }
+ }
+
+ public void HandleShutdown()
+ {
+ using (var fileLogger = new FileLogger(this.LogFilename))
+ {
+ using (ILogger logger = new TaskLoggerWrapper(fileLogger, "Shutdown"))
+ {
+ lock (this.Mutex)
+ {
+ TasksProcessor.ProcessTasks(
+ logger,
+ new ITask[]
+ {
+ new StopAudioServiceTask(),
+ new DisableAmdVideoTask(),
+ new EnableVirtualVideoTask(),
+ });
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/Program.cs b/RadeonResetBugFixService/Program.cs
new file mode 100644
index 0000000..9a5516b
--- /dev/null
+++ b/RadeonResetBugFixService/Program.cs
@@ -0,0 +1,118 @@
+namespace RadeonResetBugFixService
+{
+ using System;
+ using System.Security.Principal;
+ using System.ServiceProcess;
+ using ThirdParty.ServiceHelpers;
+
+ public static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ public static int Main(string[] args)
+ {
+ if (Environment.UserInteractive)
+ {
+ if (!HasAdministratorPrivileges())
+ {
+ Console.Error.WriteLine("Access Denied.");
+ Console.Error.WriteLine("Administrator permissions are needed to use the selected options.");
+ Console.Error.WriteLine("Use an administrator command prompt to complete these tasks.");
+ return 740; // ERROR_ELEVATION_REQUIRED
+ }
+
+ MainConsole(args);
+ return 0;
+ }
+ else
+ {
+ return MainService();
+ }
+ }
+
+ private static int MainService()
+ {
+ ServiceBase[] ServicesToRun;
+ ServicesToRun = new ServiceBase[]
+ {
+ new RadeonResetBugFixService()
+ };
+ ServiceBase.Run(ServicesToRun);
+
+ return 0;
+ }
+
+ private static void MainConsole(string[] args)
+ {
+ if (args.Length != 1)
+ {
+ ShowHelp();
+ return;
+ }
+
+ switch (args[0].ToLowerInvariant())
+ {
+ case "install":
+ DoInstall();
+ return;
+ case "uninstall":
+ DoUninstall();
+ return;
+ case "startup":
+ DoStartup();
+ return;
+ case "shutdown":
+ DoShutdown();
+ return;
+ default:
+ ShowHelp();
+ return;
+ }
+ }
+
+ private static void ShowHelp()
+ {
+ var exeName = Environment.GetCommandLineArgs()[0];
+ Console.WriteLine("Usage:");
+ Console.WriteLine($"\t{exeName} install");
+ Console.WriteLine("\t\tInstalls service");
+ Console.WriteLine($"\t{exeName} uninstall");
+ Console.WriteLine("\t\tUninstalls service");
+ Console.WriteLine($"\t{exeName} startup");
+ Console.WriteLine("\t\tPerforms startup sequence");
+ Console.WriteLine($"\t{exeName} shutdown");
+ Console.WriteLine("\t\tPerforms shutdown sequence");
+ }
+
+ private static void DoInstall()
+ {
+ ServiceHelpers.InstallService(nameof(RadeonResetBugFixService), typeof(RadeonResetBugFixService));
+ ServiceHelpers.StartService(nameof(RadeonResetBugFixService), typeof(RadeonResetBugFixService));
+ }
+
+ private static void DoUninstall()
+ {
+ ServiceHelpers.StopService(nameof(RadeonResetBugFixService), typeof(RadeonResetBugFixService));
+ ServiceHelpers.UninstallService(nameof(RadeonResetBugFixService), typeof(RadeonResetBugFixService));
+ }
+
+ private static void DoStartup()
+ {
+ new MainHandler().HandleStartup();
+ }
+
+ private static void DoShutdown()
+ {
+ new MainHandler().HandleShutdown();
+ }
+
+ // 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/ProjectInstaller.Designer.cs b/RadeonResetBugFixService/ProjectInstaller.Designer.cs
new file mode 100644
index 0000000..16bec57
--- /dev/null
+++ b/RadeonResetBugFixService/ProjectInstaller.Designer.cs
@@ -0,0 +1,62 @@
+namespace RadeonResetBugFixService
+{
+ partial class ProjectInstaller
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
+ this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
+ //
+ // serviceProcessInstaller1
+ //
+ this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
+ this.serviceProcessInstaller1.Password = null;
+ this.serviceProcessInstaller1.Username = null;
+ this.serviceProcessInstaller1.AfterInstall += new System.Configuration.Install.InstallEventHandler(this.serviceProcessInstaller1_AfterInstall);
+ //
+ // serviceInstaller1
+ //
+ this.serviceInstaller1.Description = "https://github.com/inga-lovinde/RadeonResetBugFixService";
+ this.serviceInstaller1.DisplayName = "Radeon Reset Bug fixing service";
+ this.serviceInstaller1.ServiceName = "RadeonResetBugFixService";
+ this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
+ this.serviceInstaller1.AfterInstall += new System.Configuration.Install.InstallEventHandler(this.serviceInstaller1_AfterInstall);
+ //
+ // ProjectInstaller
+ //
+ this.Installers.AddRange(new System.Configuration.Install.Installer[] {
+ this.serviceProcessInstaller1,
+ this.serviceInstaller1});
+
+ }
+
+ #endregion
+
+ private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
+ private System.ServiceProcess.ServiceInstaller serviceInstaller1;
+ }
+}
\ No newline at end of file
diff --git a/RadeonResetBugFixService/ProjectInstaller.cs b/RadeonResetBugFixService/ProjectInstaller.cs
new file mode 100644
index 0000000..d48a816
--- /dev/null
+++ b/RadeonResetBugFixService/ProjectInstaller.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Configuration.Install;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace RadeonResetBugFixService
+{
+ [RunInstaller(true)]
+ public partial class ProjectInstaller : System.Configuration.Install.Installer
+ {
+ public ProjectInstaller()
+ {
+ InitializeComponent();
+ }
+
+ private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
+ {
+
+ }
+
+ private void serviceProcessInstaller1_AfterInstall(object sender, InstallEventArgs e)
+ {
+
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/ProjectInstaller.resx b/RadeonResetBugFixService/ProjectInstaller.resx
new file mode 100644
index 0000000..ba986de
--- /dev/null
+++ b/RadeonResetBugFixService/ProjectInstaller.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 60
+
+
+ 229, 17
+
+
+ False
+
+
\ No newline at end of file
diff --git a/RadeonResetBugFixService/Properties/AssemblyInfo.cs b/RadeonResetBugFixService/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9aa02c4
--- /dev/null
+++ b/RadeonResetBugFixService/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("RadeonResetBugFixService")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("RadeonResetBugFixService")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1b9a6de9-69f9-48b2-b70d-632e5766404a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/RadeonResetBugFixService/RadeonResetBugFixService.Designer.cs b/RadeonResetBugFixService/RadeonResetBugFixService.Designer.cs
new file mode 100644
index 0000000..5f83ddc
--- /dev/null
+++ b/RadeonResetBugFixService/RadeonResetBugFixService.Designer.cs
@@ -0,0 +1,41 @@
+namespace RadeonResetBugFixService
+{
+ partial class RadeonResetBugFixService
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ //
+ // RadeonResetBugFixService
+ //
+ this.CanShutdown = true;
+ this.ServiceName = "RadeonResetBugFixService";
+
+ }
+
+ #endregion
+ }
+}
diff --git a/RadeonResetBugFixService/RadeonResetBugFixService.cs b/RadeonResetBugFixService/RadeonResetBugFixService.cs
new file mode 100644
index 0000000..6740ba3
--- /dev/null
+++ b/RadeonResetBugFixService/RadeonResetBugFixService.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Linq;
+using System.ServiceProcess;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RadeonResetBugFixService
+{
+ public partial class RadeonResetBugFixService : ServiceBase
+ {
+ private MainHandler Handler { get; } = new MainHandler();
+
+ public RadeonResetBugFixService()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnShutdown()
+ {
+ this.Handler.HandleShutdown();
+ }
+
+ protected override void OnStart(string[] args)
+ {
+ this.Handler.HandleStartup();
+ }
+
+ protected override void OnStop()
+ {
+ this.Handler.HandleShutdown();
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/RadeonResetBugFixService.csproj b/RadeonResetBugFixService/RadeonResetBugFixService.csproj
new file mode 100644
index 0000000..6568400
--- /dev/null
+++ b/RadeonResetBugFixService/RadeonResetBugFixService.csproj
@@ -0,0 +1,99 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {1B9A6DE9-69F9-48B2-B70D-632E5766404A}
+ Exe
+ RadeonResetBugFixService
+ RadeonResetBugFixService
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+ ProjectInstaller.cs
+
+
+ Component
+
+
+ RadeonResetBugFixService.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ProjectInstaller.cs
+
+
+ RadeonResetBugFixService.cs
+
+
+
+
\ No newline at end of file
diff --git a/RadeonResetBugFixService/RadeonResetBugFixService.resx b/RadeonResetBugFixService/RadeonResetBugFixService.resx
new file mode 100644
index 0000000..e5858cc
--- /dev/null
+++ b/RadeonResetBugFixService/RadeonResetBugFixService.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ False
+
+
\ No newline at end of file
diff --git a/RadeonResetBugFixService/Tasks/AbstractDriverTask.cs b/RadeonResetBugFixService/Tasks/AbstractDriverTask.cs
new file mode 100644
index 0000000..36d7a6a
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/AbstractDriverTask.cs
@@ -0,0 +1,52 @@
+namespace RadeonResetBugFixService.Tasks
+{
+ using System.Linq;
+ using Contracts;
+ using Devices;
+
+ abstract class AbstractDriverTask : ITask
+ {
+ protected virtual bool ShouldDisable(DeviceInfo deviceInfo) => false;
+
+ protected virtual bool ShouldEnable(DeviceInfo deviceInfo) => false;
+
+ public abstract string TaskName { get; }
+
+ void ITask.Run(ILogger logger)
+ {
+ var devices = DeviceHelper.GetDevices().ToArray();
+ foreach (var device in devices)
+ {
+ //logger.Log($"Present({device.IsPresent}) ErrorCode({device.ErrorCode}) Disabled({device.IsDisabled}) ClassName({device.ClassName}) Service({device.Service}) Manufacturer({device.Manufacturer}) Name({device.Name}) Id({device.DeviceId}) ClassGuid({device.ClassGuid})");
+ var deviceDescription = $"{device.Name} ({device.DeviceId}, {device.ClassGuid})";
+
+ if (this.ShouldDisable(device))
+ {
+ if (device.IsDisabled)
+ {
+ logger.Log($"{deviceDescription} already disabled");
+ }
+ else
+ {
+ logger.Log($"Disabling {deviceDescription}");
+ DeviceHelper.DisableDevice(device);
+ logger.Log($"Disabled {deviceDescription}");
+ }
+ }
+ else if (this.ShouldEnable(device))
+ {
+ if (!device.IsDisabled)
+ {
+ logger.Log($"{deviceDescription} already enabled");
+ }
+ else
+ {
+ logger.Log($"Enabling {deviceDescription}");
+ DeviceHelper.EnableDevice(device);
+ logger.Log($"Enabled {deviceDescription}");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/AbstractServiceTask.cs b/RadeonResetBugFixService/Tasks/AbstractServiceTask.cs
new file mode 100644
index 0000000..621233b
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/AbstractServiceTask.cs
@@ -0,0 +1,80 @@
+namespace RadeonResetBugFixService.Tasks
+{
+ using System;
+ using System.ServiceProcess;
+ using Contracts;
+
+ abstract class AbstractServiceTask : ITask
+ {
+ protected virtual bool ShouldStart(ServiceController serviceInfo) => false;
+
+ protected virtual bool ShouldStop(ServiceController serviceInfo) => false;
+
+ public abstract string TaskName { get; }
+
+ void ITask.Run(ILogger logger)
+ {
+ foreach (var originalService in ServiceController.GetServices())
+ {
+ string serviceDescription = $"{originalService.DisplayName} ({originalService.ServiceName})";
+
+ if (this.ShouldStart(originalService))
+ {
+ var service = new ServiceController(originalService.ServiceName);
+ if (service.Status == ServiceControllerStatus.Running)
+ {
+ logger.Log($"{serviceDescription} is already running");
+ }
+ else
+ {
+ if (service.Status != ServiceControllerStatus.StartPending)
+ {
+ logger.Log($"Starting service {serviceDescription}");
+ service.Start();
+ logger.Log($"Initiated service start for");
+ }
+
+ logger.Log($"Waiting for service {serviceDescription} to start");
+ service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
+ if (service.Status == ServiceControllerStatus.Running)
+ {
+ logger.Log($"Service is running");
+ }
+ else
+ {
+ logger.Log($"Failed; service state is {service.Status}");
+ }
+ }
+ }
+ else if (this.ShouldStop(originalService))
+ {
+ var service = new ServiceController(originalService.ServiceName);
+ if (service.Status == ServiceControllerStatus.Stopped)
+ {
+ logger.Log($"{serviceDescription} is already stopped");
+ }
+ else
+ {
+ if (service.Status != ServiceControllerStatus.StopPending)
+ {
+ logger.Log($"Stopping service {serviceDescription}");
+ service.Stop();
+ logger.Log($"Initiated service stop");
+ }
+
+ logger.Log($"Waiting for service {serviceDescription} to stop");
+ service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(15));
+ if (service.Status == ServiceControllerStatus.Stopped)
+ {
+ logger.Log($"Service is stopped");
+ }
+ else
+ {
+ logger.Log($"Failed; service state is {service.Status}");
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/DisableAmdVideoTask.cs b/RadeonResetBugFixService/Tasks/DisableAmdVideoTask.cs
new file mode 100644
index 0000000..fe63086
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/DisableAmdVideoTask.cs
@@ -0,0 +1,13 @@
+using RadeonResetBugFixService.Contracts;
+
+namespace RadeonResetBugFixService.Tasks
+{
+ using Contracts;
+ using Devices;
+
+ class DisableAmdVideoTask : AbstractDriverTask
+ {
+ public override string TaskName => "Disabling AMD video";
+ protected override bool ShouldDisable(DeviceInfo deviceInfo) => KnownDevices.IsAmdVideo(deviceInfo);
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/DisableVirtualVideoTask.cs b/RadeonResetBugFixService/Tasks/DisableVirtualVideoTask.cs
new file mode 100644
index 0000000..fac89e2
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/DisableVirtualVideoTask.cs
@@ -0,0 +1,12 @@
+namespace RadeonResetBugFixService.Tasks
+{
+ using Contracts;
+ using Devices;
+
+ class DisableVirtualVideoTask : AbstractDriverTask
+ {
+ public override string TaskName => "Disabling virtual video";
+
+ protected override bool ShouldDisable(DeviceInfo deviceInfo) => KnownDevices.IsVirtualVideo(deviceInfo);
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/EnableAmdVideoTask.cs b/RadeonResetBugFixService/Tasks/EnableAmdVideoTask.cs
new file mode 100644
index 0000000..fc82a45
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/EnableAmdVideoTask.cs
@@ -0,0 +1,13 @@
+namespace RadeonResetBugFixService.Tasks
+{
+ using Contracts;
+ using Devices;
+
+ class EnableAmdVideoTask : AbstractDriverTask
+ {
+ public override string TaskName => "Enabling AMD video";
+
+ protected override bool ShouldEnable(DeviceInfo deviceInfo) => KnownDevices.IsAmdVideo(deviceInfo);
+
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/EnableVirtualVideoTask.cs b/RadeonResetBugFixService/Tasks/EnableVirtualVideoTask.cs
new file mode 100644
index 0000000..83cd82e
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/EnableVirtualVideoTask.cs
@@ -0,0 +1,12 @@
+namespace RadeonResetBugFixService.Tasks
+{
+ using Contracts;
+ using Devices;
+
+ class EnableVirtualVideoTask : AbstractDriverTask
+ {
+ public override string TaskName => "Enabling virtual video";
+
+ protected override bool ShouldEnable(DeviceInfo deviceInfo) => KnownDevices.IsVirtualVideo(deviceInfo);
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/ITask.cs b/RadeonResetBugFixService/Tasks/ITask.cs
new file mode 100644
index 0000000..e7725a0
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/ITask.cs
@@ -0,0 +1,11 @@
+namespace RadeonResetBugFixService.Tasks
+{
+ using Contracts;
+
+ interface ITask
+ {
+ string TaskName { get; }
+
+ void Run(ILogger logger);
+ }
+}
diff --git a/RadeonResetBugFixService/Tasks/StopAudioServiceTask.cs b/RadeonResetBugFixService/Tasks/StopAudioServiceTask.cs
new file mode 100644
index 0000000..fcbb3c7
--- /dev/null
+++ b/RadeonResetBugFixService/Tasks/StopAudioServiceTask.cs
@@ -0,0 +1,14 @@
+using System.ServiceProcess;
+
+namespace RadeonResetBugFixService.Tasks
+{
+ class StopAudioServiceTask : AbstractServiceTask
+ {
+ public override string TaskName => "Stopping audio service";
+
+ protected override bool ShouldStop(ServiceController serviceInfo)
+ {
+ return serviceInfo.ServiceName.ToLowerInvariant() == "audiosrv";
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/TasksProcessor.cs b/RadeonResetBugFixService/TasksProcessor.cs
new file mode 100644
index 0000000..beba7e0
--- /dev/null
+++ b/RadeonResetBugFixService/TasksProcessor.cs
@@ -0,0 +1,33 @@
+namespace RadeonResetBugFixService
+{
+ using System;
+ using Contracts;
+ using Logging;
+ using Tasks;
+
+ static class TasksProcessor
+ {
+ private static void ProcessTask(ILogger logger, ITask task)
+ {
+ using (ILogger taskLogger = new TaskLoggerWrapper(logger, task.TaskName))
+ {
+ try
+ {
+ task.Run(taskLogger);
+ }
+ catch (Exception e)
+ {
+ taskLogger.LogError(e.ToString());
+ }
+ }
+ }
+
+ public static void ProcessTasks(ILogger logger, ITask[] tasks)
+ {
+ foreach (var task in tasks)
+ {
+ ProcessTask(logger, task);
+ }
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/ThirdParty/DisableDevice.cs b/RadeonResetBugFixService/ThirdParty/DisableDevice.cs
new file mode 100644
index 0000000..d5eaf5f
--- /dev/null
+++ b/RadeonResetBugFixService/ThirdParty/DisableDevice.cs
@@ -0,0 +1,368 @@
+namespace RadeonResetBugFixService.ThirdParty.DisableDevice
+{
+ // Code taken from https://stackoverflow.com/a/1610140
+
+ using System;
+ using System.Text;
+ using System.Collections.Generic;
+ using System.Runtime.InteropServices;
+ using System.ComponentModel;
+ using Microsoft.Win32.SafeHandles;
+ using System.Security;
+ using System.Runtime.ConstrainedExecution;
+
+
+ [Flags()]
+ internal enum SetupDiGetClassDevsFlags
+ {
+ Default = 1,
+ Present = 2,
+ AllClasses = 4,
+ Profile = 8,
+ DeviceInterface = (int)0x10
+ }
+
+ internal enum DiFunction
+ {
+ SelectDevice = 1,
+ InstallDevice = 2,
+ AssignResources = 3,
+ Properties = 4,
+ Remove = 5,
+ FirstTimeSetup = 6,
+ FoundDevice = 7,
+ SelectClassDrivers = 8,
+ ValidateClassDrivers = 9,
+ InstallClassDrivers = (int)0xa,
+ CalcDiskSpace = (int)0xb,
+ DestroyPrivateData = (int)0xc,
+ ValidateDriver = (int)0xd,
+ Detect = (int)0xf,
+ InstallWizard = (int)0x10,
+ DestroyWizardData = (int)0x11,
+ PropertyChange = (int)0x12,
+ EnableClass = (int)0x13,
+ DetectVerify = (int)0x14,
+ InstallDeviceFiles = (int)0x15,
+ UnRemove = (int)0x16,
+ SelectBestCompatDrv = (int)0x17,
+ AllowInstall = (int)0x18,
+ RegisterDevice = (int)0x19,
+ NewDeviceWizardPreSelect = (int)0x1a,
+ NewDeviceWizardSelect = (int)0x1b,
+ NewDeviceWizardPreAnalyze = (int)0x1c,
+ NewDeviceWizardPostAnalyze = (int)0x1d,
+ NewDeviceWizardFinishInstall = (int)0x1e,
+ Unused1 = (int)0x1f,
+ InstallInterfaces = (int)0x20,
+ DetectCancel = (int)0x21,
+ RegisterCoInstallers = (int)0x22,
+ AddPropertyPageAdvanced = (int)0x23,
+ AddPropertyPageBasic = (int)0x24,
+ Reserved1 = (int)0x25,
+ Troubleshooter = (int)0x26,
+ PowerMessageWake = (int)0x27,
+ AddRemotePropertyPageAdvanced = (int)0x28,
+ UpdateDriverUI = (int)0x29,
+ Reserved2 = (int)0x30
+ }
+
+ internal enum StateChangeAction
+ {
+ Enable = 1,
+ Disable = 2,
+ PropChange = 3,
+ Start = 4,
+ Stop = 5
+ }
+
+ [Flags()]
+ internal enum Scopes
+ {
+ Global = 1,
+ ConfigSpecific = 2,
+ ConfigGeneral = 4
+ }
+
+ internal enum SetupApiError
+ {
+ NoAssociatedClass = unchecked((int)0xe0000200),
+ ClassMismatch = unchecked((int)0xe0000201),
+ DuplicateFound = unchecked((int)0xe0000202),
+ NoDriverSelected = unchecked((int)0xe0000203),
+ KeyDoesNotExist = unchecked((int)0xe0000204),
+ InvalidDevinstName = unchecked((int)0xe0000205),
+ InvalidClass = unchecked((int)0xe0000206),
+ DevinstAlreadyExists = unchecked((int)0xe0000207),
+ DevinfoNotRegistered = unchecked((int)0xe0000208),
+ InvalidRegProperty = unchecked((int)0xe0000209),
+ NoInf = unchecked((int)0xe000020a),
+ NoSuchHDevinst = unchecked((int)0xe000020b),
+ CantLoadClassIcon = unchecked((int)0xe000020c),
+ InvalidClassInstaller = unchecked((int)0xe000020d),
+ DiDoDefault = unchecked((int)0xe000020e),
+ DiNoFileCopy = unchecked((int)0xe000020f),
+ InvalidHwProfile = unchecked((int)0xe0000210),
+ NoDeviceSelected = unchecked((int)0xe0000211),
+ DevinfolistLocked = unchecked((int)0xe0000212),
+ DevinfodataLocked = unchecked((int)0xe0000213),
+ DiBadPath = unchecked((int)0xe0000214),
+ NoClassInstallParams = unchecked((int)0xe0000215),
+ FileQueueLocked = unchecked((int)0xe0000216),
+ BadServiceInstallSect = unchecked((int)0xe0000217),
+ NoClassDriverList = unchecked((int)0xe0000218),
+ NoAssociatedService = unchecked((int)0xe0000219),
+ NoDefaultDeviceInterface = unchecked((int)0xe000021a),
+ DeviceInterfaceActive = unchecked((int)0xe000021b),
+ DeviceInterfaceRemoved = unchecked((int)0xe000021c),
+ BadInterfaceInstallSect = unchecked((int)0xe000021d),
+ NoSuchInterfaceClass = unchecked((int)0xe000021e),
+ InvalidReferenceString = unchecked((int)0xe000021f),
+ InvalidMachineName = unchecked((int)0xe0000220),
+ RemoteCommFailure = unchecked((int)0xe0000221),
+ MachineUnavailable = unchecked((int)0xe0000222),
+ NoConfigMgrServices = unchecked((int)0xe0000223),
+ InvalidPropPageProvider = unchecked((int)0xe0000224),
+ NoSuchDeviceInterface = unchecked((int)0xe0000225),
+ DiPostProcessingRequired = unchecked((int)0xe0000226),
+ InvalidCOInstaller = unchecked((int)0xe0000227),
+ NoCompatDrivers = unchecked((int)0xe0000228),
+ NoDeviceIcon = unchecked((int)0xe0000229),
+ InvalidInfLogConfig = unchecked((int)0xe000022a),
+ DiDontInstall = unchecked((int)0xe000022b),
+ InvalidFilterDriver = unchecked((int)0xe000022c),
+ NonWindowsNTDriver = unchecked((int)0xe000022d),
+ NonWindowsDriver = unchecked((int)0xe000022e),
+ NoCatalogForOemInf = unchecked((int)0xe000022f),
+ DevInstallQueueNonNative = unchecked((int)0xe0000230),
+ NotDisableable = unchecked((int)0xe0000231),
+ CantRemoveDevinst = unchecked((int)0xe0000232),
+ InvalidTarget = unchecked((int)0xe0000233),
+ DriverNonNative = unchecked((int)0xe0000234),
+ InWow64 = unchecked((int)0xe0000235),
+ SetSystemRestorePoint = unchecked((int)0xe0000236),
+ IncorrectlyCopiedInf = unchecked((int)0xe0000237),
+ SceDisabled = unchecked((int)0xe0000238),
+ UnknownException = unchecked((int)0xe0000239),
+ PnpRegistryError = unchecked((int)0xe000023a),
+ RemoteRequestUnsupported = unchecked((int)0xe000023b),
+ NotAnInstalledOemInf = unchecked((int)0xe000023c),
+ InfInUseByDevices = unchecked((int)0xe000023d),
+ DiFunctionObsolete = unchecked((int)0xe000023e),
+ NoAuthenticodeCatalog = unchecked((int)0xe000023f),
+ AuthenticodeDisallowed = unchecked((int)0xe0000240),
+ AuthenticodeTrustedPublisher = unchecked((int)0xe0000241),
+ AuthenticodeTrustNotEstablished = unchecked((int)0xe0000242),
+ AuthenticodePublisherNotTrusted = unchecked((int)0xe0000243),
+ SignatureOSAttributeMismatch = unchecked((int)0xe0000244),
+ OnlyValidateViaAuthenticode = unchecked((int)0xe0000245)
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct DeviceInfoData
+ {
+ public int Size;
+ public Guid ClassGuid;
+ public int DevInst;
+ public IntPtr Reserved;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PropertyChangeParameters
+ {
+ public int Size;
+ // part of header. It's flattened out into 1 structure.
+ public DiFunction DiFunction;
+ public StateChangeAction StateChange;
+ public Scopes Scope;
+ public int HwProfile;
+ }
+
+ internal class NativeMethods
+ {
+
+ private const string setupapi = "setupapi.dll";
+
+ private NativeMethods()
+ {
+ }
+
+ [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetupDiCallClassInstaller(DiFunction installFunction, SafeDeviceInfoSetHandle deviceInfoSet, [In()]
+ref DeviceInfoData deviceInfoData);
+
+ [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetupDiEnumDeviceInfo(SafeDeviceInfoSetHandle deviceInfoSet, int memberIndex, ref DeviceInfoData deviceInfoData);
+
+ [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern SafeDeviceInfoSetHandle SetupDiGetClassDevs([In()]
+ref Guid classGuid, [MarshalAs(UnmanagedType.LPWStr)]
+string enumerator, IntPtr hwndParent, SetupDiGetClassDevsFlags flags);
+
+ /*
+ [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetupDiGetDeviceInstanceId(SafeDeviceInfoSetHandle deviceInfoSet, [In()]
+ref DeviceInfoData did, [MarshalAs(UnmanagedType.LPTStr)]
+StringBuilder deviceInstanceId, int deviceInstanceIdSize, [Out()]
+ref int requiredSize);
+ */
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetupDiGetDeviceInstanceId(
+ IntPtr DeviceInfoSet,
+ ref DeviceInfoData did,
+ [MarshalAs(UnmanagedType.LPTStr)] StringBuilder DeviceInstanceId,
+ int DeviceInstanceIdSize,
+ out int RequiredSize
+ );
+
+ [SuppressUnmanagedCodeSecurity()]
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
+
+ [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetupDiSetClassInstallParams(SafeDeviceInfoSetHandle deviceInfoSet, [In()]
+ref DeviceInfoData deviceInfoData, [In()]
+ref PropertyChangeParameters classInstallParams, int classInstallParamsSize);
+
+ }
+
+ internal class SafeDeviceInfoSetHandle : SafeHandleZeroOrMinusOneIsInvalid
+ {
+
+ public SafeDeviceInfoSetHandle()
+ : base(true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ return NativeMethods.SetupDiDestroyDeviceInfoList(this.handle);
+ }
+
+ }
+
+ public sealed class DeviceHelper
+ {
+
+ private DeviceHelper()
+ {
+ }
+
+ ///
+ /// Enable or disable a device.
+ ///
+ /// The class guid of the device. Available in the device manager.
+ /// The device instance id of the device. Available in the device manager.
+ /// True to enable, False to disable.
+ /// Will throw an exception if the device is not Disableable.
+ public static void SetDeviceEnabled(Guid classGuid, string instanceId, bool enable)
+ {
+ SafeDeviceInfoSetHandle diSetHandle = null;
+ try
+ {
+ // Get the handle to a device information set for all devices matching classGuid that are present on the
+ // system.
+ diSetHandle = NativeMethods.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, SetupDiGetClassDevsFlags.Present);
+ // Get the device information data for each matching device.
+ DeviceInfoData[] diData = GetDeviceInfoData(diSetHandle);
+ // Find the index of our instance. i.e. the touchpad mouse - I have 3 mice attached...
+ int index = GetIndexOfInstance(diSetHandle, diData, instanceId);
+ // Disable...
+ EnableDevice(diSetHandle, diData[index], enable);
+ }
+ finally
+ {
+ if (diSetHandle != null)
+ {
+ if (diSetHandle.IsClosed == false)
+ {
+ diSetHandle.Close();
+ }
+ diSetHandle.Dispose();
+ }
+ }
+ }
+
+ private static DeviceInfoData[] GetDeviceInfoData(SafeDeviceInfoSetHandle handle)
+ {
+ List data = new List();
+ DeviceInfoData did = new DeviceInfoData();
+ int didSize = Marshal.SizeOf(did);
+ did.Size = didSize;
+ int index = 0;
+ while (NativeMethods.SetupDiEnumDeviceInfo(handle, index, ref did))
+ {
+ data.Add(did);
+ index += 1;
+ did = new DeviceInfoData();
+ did.Size = didSize;
+ }
+ return data.ToArray();
+ }
+
+ // Find the index of the particular DeviceInfoData for the instanceId.
+ private static int GetIndexOfInstance(SafeDeviceInfoSetHandle handle, DeviceInfoData[] diData, string instanceId)
+ {
+ const int ERROR_INSUFFICIENT_BUFFER = 122;
+ for (int index = 0; index <= diData.Length - 1; index++)
+ {
+ StringBuilder sb = new StringBuilder(1);
+ int requiredSize = 0;
+ bool result = NativeMethods.SetupDiGetDeviceInstanceId(handle.DangerousGetHandle(), ref diData[index], sb, sb.Capacity, out requiredSize);
+ if (result == false && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ sb.Capacity = requiredSize;
+ result = NativeMethods.SetupDiGetDeviceInstanceId(handle.DangerousGetHandle(), ref diData[index], sb, sb.Capacity, out requiredSize);
+ }
+ if (result == false)
+ throw new Win32Exception();
+ if (instanceId.Equals(sb.ToString()))
+ {
+ return index;
+ }
+ }
+ // not found
+ return -1;
+ }
+
+ // enable/disable...
+ private static void EnableDevice(SafeDeviceInfoSetHandle handle, DeviceInfoData diData, bool enable)
+ {
+ PropertyChangeParameters @params = new PropertyChangeParameters();
+ // The size is just the size of the header, but we've flattened the structure.
+ // The header comprises the first two fields, both integer.
+ @params.Size = 8;
+ @params.DiFunction = DiFunction.PropertyChange;
+ @params.Scope = Scopes.Global;
+ if (enable)
+ {
+ @params.StateChange = StateChangeAction.Enable;
+ }
+ else
+ {
+ @params.StateChange = StateChangeAction.Disable;
+ }
+
+ bool result = NativeMethods.SetupDiSetClassInstallParams(handle, ref diData, ref @params, Marshal.SizeOf(@params));
+ if (result == false) throw new Win32Exception();
+ result = NativeMethods.SetupDiCallClassInstaller(DiFunction.PropertyChange, handle, ref diData);
+ if (result == false)
+ {
+ int err = Marshal.GetLastWin32Error();
+ if (err == (int)SetupApiError.NotDisableable)
+ throw new ArgumentException("Device can't be disabled (programmatically or in Device Manager).");
+ else if (err >= (int)SetupApiError.NoAssociatedClass && err <= (int)SetupApiError.OnlyValidateViaAuthenticode)
+ throw new Win32Exception("SetupAPI error: " + ((SetupApiError)err).ToString());
+ else
+ throw new Win32Exception();
+ }
+ }
+ }
+}
diff --git a/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs b/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs
new file mode 100644
index 0000000..2997913
--- /dev/null
+++ b/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs
@@ -0,0 +1,122 @@
+namespace RadeonResetBugFixService.ThirdParty.ServiceHelpers
+{
+ // Code taken from https://stackoverflow.com/a/1195621 and lightly modified
+
+ using System;
+ using System.Collections;
+ using System.Configuration.Install;
+ using System.ServiceProcess;
+
+ class ServiceHelpers
+ {
+ public static bool IsInstalled(string serviceName)
+ {
+ using (ServiceController controller = new ServiceController(serviceName))
+ {
+ try
+ {
+ ServiceControllerStatus status = controller.Status;
+ }
+ catch
+ {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public static bool IsRunning(string serviceName)
+ {
+ using (ServiceController controller = new ServiceController(serviceName))
+ {
+ if (!IsInstalled(serviceName)) return false;
+ return (controller.Status == ServiceControllerStatus.Running);
+ }
+ }
+
+ public static AssemblyInstaller GetInstaller(Type serviceType)
+ {
+ AssemblyInstaller installer = new AssemblyInstaller(serviceType.Assembly, null);
+ installer.UseNewContext = true;
+ return installer;
+ }
+
+ public static void InstallService(string serviceName, Type serviceType)
+ {
+ if (IsInstalled(serviceName))
+ {
+ Console.WriteLine("Already installed");
+ return;
+ }
+
+ using (AssemblyInstaller installer = GetInstaller(serviceType))
+ {
+ IDictionary state = new Hashtable();
+ try
+ {
+ installer.Install(state);
+ installer.Commit(state);
+ Console.WriteLine("installed");
+ }
+ catch
+ {
+ try
+ {
+ installer.Rollback(state);
+ }
+ catch { }
+ throw;
+ }
+ }
+ }
+
+ public static void UninstallService(string serviceName, Type serviceType)
+ {
+ if (!IsInstalled(serviceName))
+ {
+ Console.WriteLine("Service not installed");
+ return;
+ }
+
+ using (AssemblyInstaller installer = GetInstaller(serviceType))
+ {
+ IDictionary state = new Hashtable();
+ try
+ {
+ installer.Uninstall(state);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+
+ public static void StartService(string serviceName, Type serviceType)
+ {
+ if (!IsInstalled(serviceName)) return;
+
+ using (ServiceController controller = new ServiceController(serviceName))
+ {
+ if (controller.Status != ServiceControllerStatus.Running)
+ {
+ controller.Start();
+ controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(10));
+ }
+ }
+ }
+
+ public static void StopService(string serviceName, Type serviceType)
+ {
+ if (!IsInstalled(serviceName)) return;
+ using (ServiceController controller = new ServiceController(serviceName))
+ {
+ if (controller.Status != ServiceControllerStatus.Stopped)
+ {
+ controller.Stop();
+ controller.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
+ }
+ }
+ }
+ }
+}