Naive implementation

master
Inga 🏳‍🌈 4 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;
}
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()
{
}
/// <summary>
/// Enable or disable a device.
/// </summary>
/// <param name="classGuid">The class guid of the device. Available in the device manager.</param>
/// <param name="instanceId">The device instance id of the device. Available in the device manager.</param>
/// <param name="enable">True to enable, False to disable.</param>
/// <remarks>Will throw an exception if the device is not Disableable.</remarks>
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<DeviceInfoData> data = new List<DeviceInfoData>();
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();
}
}
}
}

@ -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));
}
}
}
}
}
Loading…
Cancel
Save