Naive implementation

master
Inga 🏳‍🌈 5 years ago
parent 4f9b5b194f
commit 3282196d71
  1. 25
      RadeonResetBugFix.sln
  2. 6
      RadeonResetBugFixService/App.config
  3. 25
      RadeonResetBugFixService/Contracts/DeviceInfo.cs
  4. 10
      RadeonResetBugFixService/Contracts/ILogger.cs
  5. 83
      RadeonResetBugFixService/Devices/DeviceHelper.cs
  6. 18
      RadeonResetBugFixService/Devices/KnownDevices.cs
  7. 26
      RadeonResetBugFixService/Logging/FileLogger.cs
  8. 26
      RadeonResetBugFixService/Logging/TaskLoggerWrapper.cs
  9. 66
      RadeonResetBugFixService/MainHandler.cs
  10. 118
      RadeonResetBugFixService/Program.cs
  11. 62
      RadeonResetBugFixService/ProjectInstaller.Designer.cs
  12. 29
      RadeonResetBugFixService/ProjectInstaller.cs
  13. 129
      RadeonResetBugFixService/ProjectInstaller.resx
  14. 36
      RadeonResetBugFixService/Properties/AssemblyInfo.cs
  15. 41
      RadeonResetBugFixService/RadeonResetBugFixService.Designer.cs
  16. 37
      RadeonResetBugFixService/RadeonResetBugFixService.cs
  17. 99
      RadeonResetBugFixService/RadeonResetBugFixService.csproj
  18. 123
      RadeonResetBugFixService/RadeonResetBugFixService.resx
  19. 52
      RadeonResetBugFixService/Tasks/AbstractDriverTask.cs
  20. 80
      RadeonResetBugFixService/Tasks/AbstractServiceTask.cs
  21. 13
      RadeonResetBugFixService/Tasks/DisableAmdVideoTask.cs
  22. 12
      RadeonResetBugFixService/Tasks/DisableVirtualVideoTask.cs
  23. 13
      RadeonResetBugFixService/Tasks/EnableAmdVideoTask.cs
  24. 12
      RadeonResetBugFixService/Tasks/EnableVirtualVideoTask.cs
  25. 11
      RadeonResetBugFixService/Tasks/ITask.cs
  26. 14
      RadeonResetBugFixService/Tasks/StopAudioServiceTask.cs
  27. 33
      RadeonResetBugFixService/TasksProcessor.cs
  28. 368
      RadeonResetBugFixService/ThirdParty/DisableDevice.cs
  29. 122
      RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs

@ -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

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

@ -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; }
}
}

@ -0,0 +1,10 @@
namespace RadeonResetBugFixService.Contracts
{
using System;
interface ILogger : IDisposable
{
void Log(string message);
void LogError(string message);
}
}

@ -0,0 +1,83 @@
namespace RadeonResetBugFixService.Devices
{
using System;
using System.Collections.Generic;
using System.Management;
using Contracts;
class DeviceHelper
{
private static T GetProperty<T>(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<string>(deviceProperties, "ClassGuid")),
ClassName = GetProperty<string>(deviceProperties, "PNPClass") ?? string.Empty,
DeviceId = GetProperty<string>(deviceProperties, "PNPDeviceId") ?? string.Empty,
ErrorCode = GetProperty<UInt32>(deviceProperties, "ConfigManagerErrorCode"),
IsPresent = GetProperty<bool>(deviceProperties, "Present"),
Manufacturer = GetProperty<string>(deviceProperties, "Manufacturer") ?? string.Empty,
Name = GetProperty<string>(deviceProperties, "Name") ?? string.Empty,
Service = GetProperty<string>(deviceProperties, "Service") ?? string.Empty,
};
}
public static IEnumerable<DeviceInfo> 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);
}
}
}

@ -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";
}
}
}

@ -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()
{
}
}
}

@ -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");
}
}

@ -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(),
});
}
}
}
}
}
}

@ -0,0 +1,118 @@
namespace RadeonResetBugFixService
{
using System;
using System.Security.Principal;
using System.ServiceProcess;
using ThirdParty.ServiceHelpers;
public static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
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);
}
}
}

@ -0,0 +1,62 @@
namespace RadeonResetBugFixService
{
partial class ProjectInstaller
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

@ -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)
{
}
}
}

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="serviceProcessInstaller1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 60</value>
</metadata>
<metadata name="serviceInstaller1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>229, 17</value>
</metadata>
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>

@ -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")]

@ -0,0 +1,41 @@
namespace RadeonResetBugFixService
{
partial class RadeonResetBugFixService
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// RadeonResetBugFixService
//
this.CanShutdown = true;
this.ServiceName = "RadeonResetBugFixService";
}
#endregion
}
}

@ -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();
}
}
}

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1B9A6DE9-69F9-48B2-B70D-632E5766404A}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>RadeonResetBugFixService</RootNamespace>
<AssemblyName>RadeonResetBugFixService</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Contracts\DeviceInfo.cs" />
<Compile Include="Devices\KnownDevices.cs" />
<Compile Include="Logging\FileLogger.cs" />
<Compile Include="Contracts\ILogger.cs" />
<Compile Include="MainHandler.cs" />
<Compile Include="ProjectInstaller.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ProjectInstaller.Designer.cs">
<DependentUpon>ProjectInstaller.cs</DependentUpon>
</Compile>
<Compile Include="RadeonResetBugFixService.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="RadeonResetBugFixService.Designer.cs">
<DependentUpon>RadeonResetBugFixService.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Logging\TaskLoggerWrapper.cs" />
<Compile Include="ThirdParty\ServiceHelpers.cs" />
<Compile Include="TasksProcessor.cs" />
<Compile Include="Tasks\AbstractDriverTask.cs" />
<Compile Include="Tasks\AbstractServiceTask.cs" />
<Compile Include="Tasks\DisableAmdVideoTask.cs" />
<Compile Include="Tasks\DisableVirtualVideoTask.cs" />
<Compile Include="Tasks\EnableAmdVideoTask.cs" />
<Compile Include="Tasks\EnableVirtualVideoTask.cs" />
<Compile Include="Tasks\ITask.cs" />
<Compile Include="Tasks\StopAudioServiceTask.cs" />
<Compile Include="ThirdParty\DisableDevice.cs" />
<Compile Include="Devices\DeviceHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ProjectInstaller.resx">
<DependentUpon>ProjectInstaller.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="RadeonResetBugFixService.resx">
<DependentUpon>RadeonResetBugFixService.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>

@ -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}");
}
}
}
}
}
}

@ -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}");
}
}
}
}
}
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -0,0 +1,11 @@
namespace RadeonResetBugFixService.Tasks
{
using Contracts;
interface ITask
{
string TaskName { get; }
void Run(ILogger logger);
}
}

@ -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";
}
}
}

@ -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);
}
}
}
}

@ -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;
}