From 5f2990d3d14982826edc0f311db55b0e16c49670 Mon Sep 17 00:00:00 2001 From: Greg Seaton Date: Wed, 15 Apr 2026 01:35:36 -0400 Subject: [PATCH 1/4] local dev and testing on linux --- Directory.Build.props | 37 +++++++++++++++++++++++++------------ build/build.sh | 13 +++++++++++++ build/publish.sh | 28 ++++++++++++++++++++++++++++ build/test.sh | 32 ++++++++++++++++++++++++++++++++ local-ci.sh | 23 +++++++++++++++++++++++ 5 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 build/build.sh create mode 100644 build/publish.sh create mode 100644 build/test.sh create mode 100644 local-ci.sh diff --git a/Directory.Build.props b/Directory.Build.props index f88659d..1fb56c8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,26 +1,38 @@ + net9.0-windows;net8.0-windows;net48 win-x64 x64 - - - 7.3 - - True - True - True - latest - True - - true + false false true false false false - false en-US + + 7.3 + + + true + + + true + true + true + true + true + latest + 9999 + + + true + $(MSBuildThisFileDirectory)/artifacts + + + False + False @@ -28,6 +40,7 @@ + true diff --git a/build/build.sh b/build/build.sh new file mode 100644 index 0000000..d653ed5 --- /dev/null +++ b/build/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -eu + + +version=$BUILD_VERSION +echo "Version: ${version}" + +echo '***** Building solution...' +dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net9.0-windows +dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net8.0-windows +#dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net48 +echo '***** Done Building solution...' diff --git a/build/publish.sh b/build/publish.sh new file mode 100644 index 0000000..eba59e7 --- /dev/null +++ b/build/publish.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -eu + + +version=BUILD_VERSION +echo"Version: ${version}" + + +echo '***** Publishing Application...' +dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net9.0-windows +dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net8.0-windows +#dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net48 +echo '***** Done Publishing Application...' + + +echo '***** Archiving Application...' +publishSrcDir='./artifacts/publish/RadeonSoftwareSlimmer' +publishDestDir='./artifacts/publish' + +zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net90.zip" "${publishSrcDir}/release_net9.0-windows_win-x64/*" +zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net80.zip" "${publishSrcDir}/release_net8.0-windows_win-x64/*" +#zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net48.zip" "${publishSrcDir}/release_net48_win-x64/*" +echo '***** Done Archiving Application...' + + +echo '***** Archive Hashes (SHA256):' +sha256sum "${publishDestDir}\RadeonSoftwareSlimmer_*_net*.zip" diff --git a/build/test.sh b/build/test.sh new file mode 100644 index 0000000..c643489 --- /dev/null +++ b/build/test.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +set -eu + + +artifactPath='./artifacts' +resultsPath='./artifacts/tests' + + +echo '***** Installing Report Generator...' +dotnet tool install dotnet-reportgenerator-globaltool --tool-path $artifactPath + + +echo '***** Testing solution...' +# https://github.com/dotnet/sdk/issues/44991 - does not support artifact output +project='./test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj' + +dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net9.0-windows +dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net8.0-windows +#dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net48 +echo '***** Done Testing solution...' + + +echo '***** Running Report Generator...' +#$reportGenArgs = @( +# "-reports:${resultsPath}\*\coverage.cobertura*.xml", +# "-targetdir:${artifactPath}\CoverageReports", +# '-reporttypes:Badges;Cobertura;Html;HtmlSummary;TextSummary', +# '--settings:createSubdirectoryForAllReportTypes=true' +#) +#Start-Process -FilePath "${artifactPath}\reportgenerator.exe" -ArgumentList $reportGenArgs -NoNewWindow -Wait +#Get-Content -Path "${artifactPath}\CoverageReports\TextSummary\Summary.txt" diff --git a/local-ci.sh b/local-ci.sh new file mode 100644 index 0000000..bd2e5be --- /dev/null +++ b/local-ci.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -eu + + +export BUILD_VERSION='1.2.3-localci' + +echo '***** Recreating artifacts directory...' +artifactPath='./artifacts' +echo $artifactPath +if [[ -d "${artifactPath}" ]]; then + rm --recursive --force "${artifactPath:?}/*" +fi + + +bash ./build/build.sh + +bash ./build/test.sh + +bash ./build/publish.sh + + +echo '***** Done!' From 2d1fe113d9fddaa199bd513f2c8c5090b2d6aeec Mon Sep 17 00:00:00 2001 From: Greg Seaton Date: Sat, 25 Apr 2026 03:07:23 -0400 Subject: [PATCH 2/4] check in current progress, splitting out projects --- .gitignore | 67 +++++++--- .vscode/extensions.json | 14 ++ Directory.Build.props | 16 +-- Directory.Packages.props | 22 ++++ README.md | 43 ++----- RadeonSoftwareSlimmer.sln | 66 ++++++++-- build/build.sh | 5 +- build/publish.sh | 10 +- build/test.sh | 5 +- .../Enums/RegistryValueKind.cs | 15 +++ .../Interfaces/IAppLogger.cs | 16 +++ .../Interfaces/IProcessHandler.cs | 11 ++ .../Interfaces/IProcessRunner.cs | 9 ++ .../Interfaces}/IRegistry.cs | 2 +- .../Interfaces}/IRegistryKey.cs | 4 +- .../PreInstall/DisplayComponentListModel.cs | 12 +- .../PreInstall/DisplayComponentModel.cs | 18 +-- .../PreInstall/InstallerFilesModel.cs | 46 +++---- .../PreInstall/PackageListModel.cs | 20 +-- .../PreInstall/PackageModel.cs | 2 +- .../PreInstall/ScheduledTaskXmlListModel.cs | 16 ++- .../PreInstall/ScheduledTaskXmlModel.cs | 2 +- .../RadeonSoftwareSlimmer.Core.csproj | 17 +++ .../Services/ProcessHandler.cs | 72 +++++++++++ .../Services/ProcessRunner.cs | 50 ++++++++ .../RadeonSoftwareSlimmer.Windows.csproj | 23 ++++ .../WindowsRegistry.cs | 4 +- .../WindowsRegistryKey.cs | 8 +- .../Models/PostInstall/HostServiceModel.cs | 7 +- .../Models/PostInstall/InstalledListModel.cs | 2 +- .../Models/PostInstall/InstalledModel.cs | 2 +- .../Models/PostInstall/ServiceListModel.cs | 2 +- .../Models/PostInstall/ServiceModel.cs | 5 +- .../PostInstall/WindowsAppStartupModel.cs | 4 +- .../RadeonSoftwareSlimmer.csproj | 34 +++-- .../Services/ProcessHandler.cs | 120 ------------------ .../Services/ThemeService.cs | 2 +- src/Shared/Shared.shproj | 1 - .../RadeonSoftwareSlimmer.Core.Test.csproj | 41 ++++++ .../RadeonSoftwareSlimmer.Test.csproj | 31 ++--- .../RadeonSoftwareSlimmer.Windows.Test.csproj | 42 ++++++ 41 files changed, 575 insertions(+), 313 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 Directory.Packages.props create mode 100644 src/RadeonSoftwareSlimmer.Core/Enums/RegistryValueKind.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessRunner.cs rename src/{RadeonSoftwareSlimmer/Intefaces => RadeonSoftwareSlimmer.Core/Interfaces}/IRegistry.cs (73%) rename src/{RadeonSoftwareSlimmer/Intefaces => RadeonSoftwareSlimmer.Core/Interfaces}/IRegistryKey.cs (81%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/DisplayComponentListModel.cs (87%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/DisplayComponentModel.cs (85%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/InstallerFilesModel.cs (78%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/PackageListModel.cs (87%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/PackageModel.cs (96%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/ScheduledTaskXmlListModel.cs (90%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PreInstall/ScheduledTaskXmlModel.cs (95%) create mode 100644 src/RadeonSoftwareSlimmer.Core/RadeonSoftwareSlimmer.Core.csproj create mode 100644 src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs create mode 100644 src/RadeonSoftwareSlimmer.Windows/RadeonSoftwareSlimmer.Windows.csproj rename src/{RadeonSoftwareSlimmer/Services => RadeonSoftwareSlimmer.Windows}/WindowsRegistry.cs (83%) rename src/{RadeonSoftwareSlimmer/Services => RadeonSoftwareSlimmer.Windows}/WindowsRegistryKey.cs (86%) delete mode 100644 src/RadeonSoftwareSlimmer/Services/ProcessHandler.cs create mode 100644 test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj create mode 100644 test/RadeonSoftwareSlimmer.Windows.Test/RadeonSoftwareSlimmer.Windows.Test.csproj diff --git a/.gitignore b/.gitignore index a4fe18b..d5a18de 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.user *.userosscache *.sln.docstates +*.env # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs @@ -21,17 +22,37 @@ mono_crash.* [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -x64/ -x86/ + +[Dd]ebug/x64/ +[Dd]ebugPublic/x64/ +[Rr]elease/x64/ +[Rr]eleases/x64/ +bin/x64/ +obj/x64/ + +[Dd]ebug/x86/ +[Dd]ebugPublic/x86/ +[Rr]elease/x86/ +[Rr]eleases/x86/ +bin/x86/ +obj/x86/ + [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ +[Aa][Rr][Mm]64[Ee][Cc]/ bld/ -[Bb]in/ [Oo]bj/ +[Oo]ut/ [Ll]og/ [Ll]ogs/ +# Build results on 'Bin' directories +**/[Bb]in/* +# Uncomment if you have tasks that rely on *.refresh files to move binaries +# (https://github.com/github/gitignore/pull/3736) +#!**/[Bb]in/*.refresh + # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot @@ -43,12 +64,16 @@ Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* +*.trx # NUnit *.VisualState.xml TestResult.xml nunit-*.xml +# Approval Tests result files +*.received.* + # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ @@ -61,6 +86,7 @@ BenchmarkDotNet.Artifacts/ project.lock.json project.fragment.lock.json artifacts/ +.artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt @@ -75,6 +101,7 @@ StyleCopReport.xml *.ilk *.meta *.obj +*.idb *.iobj *.pch *.pdb @@ -155,6 +182,7 @@ coverage*.info # NCrunch _NCrunch_* +.NCrunch_* .*crunch*.local.xml nCrunchTemp_* @@ -296,9 +324,6 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw -# Visual Studio 6 auto-generated project file (contains which files were open etc.) -*.vbp - # Visual Studio 6 workspace and project file (working project files containing files to include in project) *.dsw *.dsp @@ -316,22 +341,22 @@ node_modules/ _Pvt_Extensions # Paket dependency manager -.paket/paket.exe +**/.paket/paket.exe paket-files/ # FAKE - F# Make -.fake/ +**/.fake/ # CodeRush personal settings -.cr/personal +**/.cr/personal # Python Tools for Visual Studio (PTVS) -__pycache__/ +**/__pycache__/ *.pyc # Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config +#tools/** +#!tools/packages.config # Tabs Studio *.tss @@ -353,15 +378,19 @@ ASALocalRun/ # MSBuild Binary and Structured Log *.binlog +MSBuild_Logs/ + +# AWS SAM Build and Temporary Artifacts folder +.aws-sam # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder -.mfractor/ +**/.mfractor/ # Local History for Visual Studio -.localhistory/ +**/.localhistory/ # Visual Studio History (VSHistory) files .vshistory/ @@ -373,7 +402,7 @@ healthchecksdb MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder -.ionide/ +**/.ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd @@ -384,17 +413,17 @@ FodyWeavers.xsd !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -*.code-workspace +!.vscode/*.code-snippets # Local History for Visual Studio Code .history/ +# Built Visual Studio Code Extensions +*.vsix + # Windows Installer files from build outputs *.cab *.msi *.msix *.msm *.msp - -# JetBrains Rider -*.sln.iml diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..57526a2 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,14 @@ +{ + "recommendations": [ + "dotnetdev-kr-custom.csharp", + "editorconfig.editorconfig", + "github.vscode-github-actions", + "aliasadidev.nugetpackagemanagergui", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one", + "davidanson.vscode-markdownlint", + "ms-vscode.powershell", + "fernandoescolar.vscode-solution-explorer", + "jakubkozera.csharp-dev-tools" + ] +} \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 1fb56c8..b02ac1f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,8 +1,6 @@ - net9.0-windows;net8.0-windows;net48 - win-x64 x64 false false @@ -13,10 +11,11 @@ en-US 7.3 - + Radeon Software Slimmer + Radeon Software Slimmer + Greg Seaton true - true true @@ -25,34 +24,29 @@ true latest 9999 - true $(MSBuildThisFileDirectory)/artifacts - False False - - true - + true true - false false false - + \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..ca5d87f --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,22 @@ + + + true + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 10aae7c..26a85f3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Radeon Software Slimmer -**https://github.com/GSDragoon/RadeonSoftwareSlimmer** +**[https://github.com/GSDragoon/RadeonSoftwareSlimmer](https://github.com/GSDragoon/RadeonSoftwareSlimmer)** -![Release](https://github.com/GSDragoon/RadeonSoftwareSlimmer/workflows/Release/badge.svg) -![Continuous-Integration](https://github.com/GSDragoon/RadeonSoftwareSlimmer/workflows/Continuous-Integration/badge.svg) +![Release](https://github.com/GSDragoon/RadeonSoftwareSlimmer/workflows/Release/badge.svg) +![Continuous-Integration](https://github.com/GSDragoon/RadeonSoftwareSlimmer/workflows/Continuous%20Integration/badge.svg) ![Latest-Release-Version](https://img.shields.io/github/v/release/GSDragoon/RadeonSoftwareSlimmer?color=yellow) ![Latest-Release-Date](https://img.shields.io/github/release-date/GSDragoon/RadeonSoftwareSlimmer) @@ -14,7 +14,7 @@ Radeon Software Slimmer is a utility to trim down the "[bloat](https://en.wikipedia.org/wiki/Software_bloat)" with the [Radeon Software](https://www.amd.com/en/technologies/radeon-software) for AMD GPUs on Microsoft Windows. -Radeon Software Adrenalin 2020 Edition introduced a ton of new features. You can read about it [here](https://community.amd.com/community/gaming/blog/2019/12/10/change-the-way-you-game-with-amd-radeon-software-adrenalin-2020-edition). While many enjoy these features, there are some that do not. And to those users, they feel the software contains a lot of unnecessary bloat without any way to not install or disable it. Radeon Software Slimmer is aimed at those users who want to keep their systems as slim as possible. This software is not meant to disrespect AMD or it's hard-working employees. It was inspired by the [NVIDIA driver slimming utility](https://www.guru3d.com/files-details/nvidia-driver-slimming-utility.html). +Radeon Software Adrenalin 2020 Edition introduced a ton of new features. You can read about it [here](https://community.amd.com/community/gaming/blog/2019/12/10/change-the-way-you-game-with-amd-radeon-software-adrenalin-2020-edition). While many enjoy these features, there are some that do not. And to those users, they feel the software contains a lot of unnecessary bloat without any way to not install or disable it. Radeon Software Slimmer is aimed at those users who want to keep their systems as slim as possible. This software is not meant to disrespect AMD or it's hard-working employees. It was inspired by the [NVIDIA driver slimming utility](https://www.guru3d.com/files-details/nvidia-driver-slimming-utility.html). Radeon Software Slimmer is completely free and open source. It does not contain any advertisements, telemetry or reach out to the internet. Logging is captured within the application, for troubleshooting purposes, but does not write to file or leave the application unless you explicitly do so. @@ -29,6 +29,7 @@ Improper use could cause system instability. **Use at your own risk!** Documentation can be found on the [Wiki](https://github.com/GSDragoon/RadeonSoftwareSlimmer/wiki). Requirements: + * Administrator rights * Windows 10 64-bit or Windows 11 (Latest version recommended) * .NET (Either ***one*** of the following) @@ -38,6 +39,7 @@ Requirements: * [.NET Desktop Runtime 9.0 x64](https://dotnet.microsoft.com/download/dotnet/9.0) (latest release recommended) Installation: + 1. Download the version you want on the [Releases page](https://github.com/GSDragoon/RadeonSoftwareSlimmer/releases). 2. Extract the contents of the downloaded zip file to a folder of your choice. If upgrading from a previous version, it is highly recommended to deleted the old files first. There are no persistent configuration files or anything like that. 3. Run `RadeonSoftwareSlimmer.exe` @@ -46,28 +48,11 @@ Installation: Thanks to the following third parties used with this software: -* .NET - * https://dotnet.microsoft.com/ - * Built with .NET and related Microsoft libraries -* 7-Zip - * https://www.7-zip.org/ - * 7z.exe included in download - * Used for decompressing the Radeon Software installer files -* Radeon profile icon - * http://www.iconarchive.com/show/papirus-apps-icons-by-papirus-team/radeon-profile-icon.html - * Main application icon -* MahApps - * https://mahapps.com/ - * UI controls, styles, themes and more -* Json.NET - * https://www.newtonsoft.com/json - * Used for reading json files with the Radeon Software installer -* Task Scheduler Manged Wrapper - * https://github.com/dahall/taskscheduler - * Used to read and modify system scheduled tasks -* System.IO.Abstractions - * https://github.com/System-IO-Abstractions/System.IO.Abstractions - * Provides abstractions for System.IO for testability -* Shields.io - * https://shields.io/ - * Provides badges on readme +* [.NET](https://dotnet.microsoft.com/): Built with .NET and related Microsoft libraries +* [7-Zip](https://www.7-zip.org/): Used for decompressing the Radeon Software installer files +* [Radeon profile icon](http://www.iconarchive.com/show/papirus-apps-icons-by-papirus-team/radeon-profile-icon.html): Main application icon +* [MahApps](https://mahapps.com/): UI controls, styles, themes and more +* [Json.NET](https://www.newtonsoft.com/json): Used for reading json files with the Radeon Software installer +* [Task Scheduler Manged Wrapper](https://github.com/dahall/taskscheduler): Used to read and modify system scheduled tasks +* [System.IO.Abstractions](https://github.com/System-IO-Abstractions/System.IO.Abstractions): Provides abstractions for System.IO for testability +* [Shields.io](https://shields.io/): Provides badges on readme diff --git a/RadeonSoftwareSlimmer.sln b/RadeonSoftwareSlimmer.sln index 4c916a9..038ee9c 100644 --- a/RadeonSoftwareSlimmer.sln +++ b/RadeonSoftwareSlimmer.sln @@ -1,10 +1,8 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RadeonSoftwareSlimmer", "src\RadeonSoftwareSlimmer\RadeonSoftwareSlimmer.csproj", "{A57F631F-11BB-4D48-A795-B90039733F4C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7785ED3B-B4D4-41C1-AEBF-002B25AB3E38}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -13,11 +11,28 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution local-ci.ps1 = local-ci.ps1 nuget.config = nuget.config README.md = README.md + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + EndProjectSectionEndProjectSection = EndProjectSectionEndProjectSection EndProjectSection EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Shared", "src\Shared\Shared.shproj", "{9B80E4B0-8113-4FD6-A3B2-F67E98604F6C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RadeonSoftwareSlimmer.Test", "test\RadeonSoftwareSlimmer.Test\RadeonSoftwareSlimmer.Test.csproj", "{16BE9BC0-E55D-47B2-9B57-4F7D5D18220B}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonSoftwareSlimmer", "src\RadeonSoftwareSlimmer\RadeonSoftwareSlimmer.csproj", "{B30D2620-737A-4759-AF34-61640B5828C4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonSoftwareSlimmer.Core", "src\RadeonSoftwareSlimmer.Core\RadeonSoftwareSlimmer.Core.csproj", "{081CE27B-1523-4D66-975C-96FFCBBC4834}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonSoftwareSlimmer.Windows", "src\RadeonSoftwareSlimmer.Windows\RadeonSoftwareSlimmer.Windows.csproj", "{D3BB4636-6CA7-40F3-967C-D0C7B4BB9200}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0C88DD14-F956-CE84-757C-A364CCF449FC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonSoftwareSlimmer.Test", "test\RadeonSoftwareSlimmer.Test\RadeonSoftwareSlimmer.Test.csproj", "{1C8F9EE6-F709-45F4-A5F9-EE2D91CF52B8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonSoftwareSlimmer.Core.Test", "test\RadeonSoftwareSlimmer.Core.Test\RadeonSoftwareSlimmer.Core.Test.csproj", "{8F49B8A8-7DBF-4431-93F9-AB81DA174067}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RadeonSoftwareSlimmer.Windows.Test", "test\RadeonSoftwareSlimmer.Windows.Test\RadeonSoftwareSlimmer.Windows.Test.csproj", "{4FFEA2E1-FA92-45E7-AFB3-9FAEC127E6D5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,18 +40,45 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A57F631F-11BB-4D48-A795-B90039733F4C}.Debug|x64.ActiveCfg = Debug|x64 - {A57F631F-11BB-4D48-A795-B90039733F4C}.Debug|x64.Build.0 = Debug|x64 - {A57F631F-11BB-4D48-A795-B90039733F4C}.Release|x64.ActiveCfg = Release|x64 - {A57F631F-11BB-4D48-A795-B90039733F4C}.Release|x64.Build.0 = Release|x64 - {16BE9BC0-E55D-47B2-9B57-4F7D5D18220B}.Debug|x64.ActiveCfg = Debug|x64 - {16BE9BC0-E55D-47B2-9B57-4F7D5D18220B}.Debug|x64.Build.0 = Debug|x64 - {16BE9BC0-E55D-47B2-9B57-4F7D5D18220B}.Release|x64.ActiveCfg = Release|x64 - {16BE9BC0-E55D-47B2-9B57-4F7D5D18220B}.Release|x64.Build.0 = Release|x64 + {B30D2620-737A-4759-AF34-61640B5828C4}.Debug|x64.ActiveCfg = Debug|x64 + {B30D2620-737A-4759-AF34-61640B5828C4}.Debug|x64.Build.0 = Debug|x64 + {B30D2620-737A-4759-AF34-61640B5828C4}.Release|x64.ActiveCfg = Release|x64 + {B30D2620-737A-4759-AF34-61640B5828C4}.Release|x64.Build.0 = Release|x64 + {081CE27B-1523-4D66-975C-96FFCBBC4834}.Debug|x64.ActiveCfg = Debug|x64 + {081CE27B-1523-4D66-975C-96FFCBBC4834}.Debug|x64.Build.0 = Debug|x64 + {081CE27B-1523-4D66-975C-96FFCBBC4834}.Release|x64.ActiveCfg = Release|x64 + {081CE27B-1523-4D66-975C-96FFCBBC4834}.Release|x64.Build.0 = Release|x64 + {D3BB4636-6CA7-40F3-967C-D0C7B4BB9200}.Debug|x64.ActiveCfg = Debug|x64 + {D3BB4636-6CA7-40F3-967C-D0C7B4BB9200}.Debug|x64.Build.0 = Debug|x64 + {D3BB4636-6CA7-40F3-967C-D0C7B4BB9200}.Release|x64.ActiveCfg = Release|x64 + {D3BB4636-6CA7-40F3-967C-D0C7B4BB9200}.Release|x64.Build.0 = Release|x64 + {1C8F9EE6-F709-45F4-A5F9-EE2D91CF52B8}.Debug|x64.ActiveCfg = Debug|x64 + {1C8F9EE6-F709-45F4-A5F9-EE2D91CF52B8}.Debug|x64.Build.0 = Debug|x64 + {1C8F9EE6-F709-45F4-A5F9-EE2D91CF52B8}.Release|x64.ActiveCfg = Release|x64 + {1C8F9EE6-F709-45F4-A5F9-EE2D91CF52B8}.Release|x64.Build.0 = Release|x64 + {8F49B8A8-7DBF-4431-93F9-AB81DA174067}.Debug|x64.ActiveCfg = Debug|x64 + {8F49B8A8-7DBF-4431-93F9-AB81DA174067}.Debug|x64.Build.0 = Debug|x64 + {8F49B8A8-7DBF-4431-93F9-AB81DA174067}.Release|x64.ActiveCfg = Release|x64 + {8F49B8A8-7DBF-4431-93F9-AB81DA174067}.Release|x64.Build.0 = Release|x64 + {4FFEA2E1-FA92-45E7-AFB3-9FAEC127E6D5}.Debug|x64.ActiveCfg = Debug|x64 + {4FFEA2E1-FA92-45E7-AFB3-9FAEC127E6D5}.Debug|x64.Build.0 = Debug|x64 + {4FFEA2E1-FA92-45E7-AFB3-9FAEC127E6D5}.Release|x64.ActiveCfg = Release|x64 + {4FFEA2E1-FA92-45E7-AFB3-9FAEC127E6D5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1C8F9EE6-F709-45F4-A5F9-EE2D91CF52B8} = {0C88DD14-F956-CE84-757C-A364CCF449FC} + {8F49B8A8-7DBF-4431-93F9-AB81DA174067} = {0C88DD14-F956-CE84-757C-A364CCF449FC} + {4FFEA2E1-FA92-45E7-AFB3-9FAEC127E6D5} = {0C88DD14-F956-CE84-757C-A364CCF449FC} + + {B30D2620-737A-4759-AF34-61640B5828C4} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + + {081CE27B-1523-4D66-975C-96FFCBBC4834} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + + {D3BB4636-6CA7-40F3-967C-D0C7B4BB9200} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BACD17E6-3BDC-4AA0-AC9E-54786CEB483D} EndGlobalSection diff --git a/build/build.sh b/build/build.sh index d653ed5..5a37611 100644 --- a/build/build.sh +++ b/build/build.sh @@ -7,7 +7,8 @@ version=$BUILD_VERSION echo "Version: ${version}" echo '***** Building solution...' -dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net9.0-windows -dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net8.0-windows +dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net10.0 +#dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net9.0-windows +#dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net8.0-windows #dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net48 echo '***** Done Building solution...' diff --git a/build/publish.sh b/build/publish.sh index eba59e7..a61250b 100644 --- a/build/publish.sh +++ b/build/publish.sh @@ -8,8 +8,9 @@ echo"Version: ${version}" echo '***** Publishing Application...' -dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net9.0-windows -dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net8.0-windows +dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net10.0 +#dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net9.0-windows +#dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net8.0-windows #dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net48 echo '***** Done Publishing Application...' @@ -18,8 +19,9 @@ echo '***** Archiving Application...' publishSrcDir='./artifacts/publish/RadeonSoftwareSlimmer' publishDestDir='./artifacts/publish' -zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net90.zip" "${publishSrcDir}/release_net9.0-windows_win-x64/*" -zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net80.zip" "${publishSrcDir}/release_net8.0-windows_win-x64/*" +zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net90.zip" "${publishSrcDir}/release_net10.0-x64/*" +#zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net90.zip" "${publishSrcDir}/release_net9.0-windows_win-x64/*" +#zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net80.zip" "${publishSrcDir}/release_net8.0-windows_win-x64/*" #zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net48.zip" "${publishSrcDir}/release_net48_win-x64/*" echo '***** Done Archiving Application...' diff --git a/build/test.sh b/build/test.sh index c643489..cd8c6bd 100644 --- a/build/test.sh +++ b/build/test.sh @@ -15,8 +15,9 @@ echo '***** Testing solution...' # https://github.com/dotnet/sdk/issues/44991 - does not support artifact output project='./test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj' -dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net9.0-windows -dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net8.0-windows +dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net10.0 +#dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net9.0-windows +#dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net8.0-windows #dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net48 echo '***** Done Testing solution...' diff --git a/src/RadeonSoftwareSlimmer.Core/Enums/RegistryValueKind.cs b/src/RadeonSoftwareSlimmer.Core/Enums/RegistryValueKind.cs new file mode 100644 index 0000000..a01ee04 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Enums/RegistryValueKind.cs @@ -0,0 +1,15 @@ +namespace RadeonSoftwareSlimmer.Core.Enums +{ + // Copy of the real one + public enum RegistryValueKind : int + { + None = -1, + Unknown = 0, + String = 1, + ExpandString = 2, + Binary = 3, + DWord = 4, + MultiString = 7, + QWord = 11 + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs new file mode 100644 index 0000000..ee2fd46 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs @@ -0,0 +1,16 @@ +using System; + +namespace RadeonSoftwareSlimmer.Core.Interfaces +{ + public interface IAppLogger + { + void Info(string message); + void Info(Exception ex); + + void Debug(string message); + void Debug(Exception ex); + + void Error(Exception ex); + void Error(Exception ex, string message); + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs new file mode 100644 index 0000000..caeee92 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs @@ -0,0 +1,11 @@ +namespace RadeonSoftwareSlimmer.Core.Interfaces +{ + public interface IProcessHandler + { + bool IsProcessRunning(); + + void WaitForProcessToEnd(int maxWaitSeconds); + + void WaitForProcessToStart(int maxWaitSeconds); + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessRunner.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessRunner.cs new file mode 100644 index 0000000..160da6c --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessRunner.cs @@ -0,0 +1,9 @@ +using System; + +namespace RadeonSoftwareSlimmer.Core.Interfaces +{ + public interface IProcessRunner + { + int RunProcess(string fileName, string arguments); + } +} diff --git a/src/RadeonSoftwareSlimmer/Intefaces/IRegistry.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IRegistry.cs similarity index 73% rename from src/RadeonSoftwareSlimmer/Intefaces/IRegistry.cs rename to src/RadeonSoftwareSlimmer.Core/Interfaces/IRegistry.cs index f30f994..615f7e0 100644 --- a/src/RadeonSoftwareSlimmer/Intefaces/IRegistry.cs +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IRegistry.cs @@ -1,4 +1,4 @@ -namespace RadeonSoftwareSlimmer.Intefaces +namespace RadeonSoftwareSlimmer.Core.Interfaces { public interface IRegistry { diff --git a/src/RadeonSoftwareSlimmer/Intefaces/IRegistryKey.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IRegistryKey.cs similarity index 81% rename from src/RadeonSoftwareSlimmer/Intefaces/IRegistryKey.cs rename to src/RadeonSoftwareSlimmer.Core/Interfaces/IRegistryKey.cs index aaee5da..5e73d45 100644 --- a/src/RadeonSoftwareSlimmer/Intefaces/IRegistryKey.cs +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IRegistryKey.cs @@ -1,7 +1,7 @@ using System; -using Microsoft.Win32; +using RadeonSoftwareSlimmer.Core.Enums; -namespace RadeonSoftwareSlimmer.Intefaces +namespace RadeonSoftwareSlimmer.Core.Interfaces { public interface IRegistryKey : IDisposable { diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/DisplayComponentListModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/DisplayComponentListModel.cs similarity index 87% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/DisplayComponentListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/DisplayComponentListModel.cs index 40bd34c..e75abfe 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/DisplayComponentListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/DisplayComponentListModel.cs @@ -2,12 +2,13 @@ using System.ComponentModel; using System.IO; using System.IO.Abstractions; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { public class DisplayComponentListModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; private readonly IFileSystem _fileSystem; private IDirectoryInfo _installDir; private IDirectoryInfo _componentBaseDir; @@ -15,8 +16,9 @@ public class DisplayComponentListModel : INotifyPropertyChanged private IEnumerable _components; - public DisplayComponentListModel(IFileSystem fileSystem) + public DisplayComponentListModel(IFileSystem fileSystem, IAppLogger logger) { + _logger = logger; _fileSystem = fileSystem; } @@ -66,7 +68,7 @@ public void RestoreToDefault() { // If loading from another instance of the application, it won't have the old component information // Move also changes the original directory object's path - StaticViewModel.AddDebugMessage($"Restoring display component {backedUpComponentDir.Name} to {_componentBaseDir.FullName}"); + _logger.Debug($"Restoring display component {backedUpComponentDir.Name} to {_componentBaseDir.FullName}"); backedUpComponentDir.MoveTo(_fileSystem.Path.Combine(_componentBaseDir.FullName, backedUpComponentDir.Name)); } } @@ -79,7 +81,7 @@ private IEnumerable GetDisplayComponents() foreach (IDirectoryInfo componentDirectory in _componentBaseDir.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)) { if (componentDirectory.GetFiles("*.inf", SearchOption.TopDirectoryOnly).Length == 1) - yield return new DisplayComponentModel(_installDir, componentDirectory); + yield return new DisplayComponentModel(_installDir, componentDirectory, _logger); } } } diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/DisplayComponentModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/DisplayComponentModel.cs similarity index 85% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/DisplayComponentModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/DisplayComponentModel.cs index 37e4d79..c2ea7fb 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/DisplayComponentModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/DisplayComponentModel.cs @@ -2,20 +2,22 @@ using System.ComponentModel; using System.IO; using System.IO.Abstractions; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { public class DisplayComponentModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; private readonly IDirectoryInfo _componentDirectory; private readonly IDirectoryInfo _backupDirectory; private bool _keep; - public DisplayComponentModel(IDirectoryInfo installerRootDirectory, IDirectoryInfo componentDirectory) + public DisplayComponentModel(IDirectoryInfo installerRootDirectory, IDirectoryInfo componentDirectory, IAppLogger logger) { - StaticViewModel.AddDebugMessage($"Found display component in {componentDirectory.FullName}"); + _logger = logger; + _logger.Debug($"Found display component in {componentDirectory.FullName}"); Keep = true; @@ -52,7 +54,7 @@ public void Remove() if (Keep || !_componentDirectory.Exists) return; - StaticViewModel.AddDebugMessage($"Removing {_componentDirectory.FullName}"); + _logger.Debug($"Removing {_componentDirectory.FullName}"); foreach (IFileInfo file in _componentDirectory.EnumerateFiles("*", SearchOption.AllDirectories)) { @@ -63,7 +65,7 @@ public void Remove() } string componentBackupDir = _backupDirectory.FileSystem.Path.Combine(_backupDirectory.FullName, _componentDirectory.Name); - StaticViewModel.AddDebugMessage($"Moving display component {_componentDirectory.Name} to backup path {componentBackupDir}"); + _logger.Debug("Moving display component {_componentDirectory.Name} to backup path {componentBackupDir}"); _componentDirectory.MoveTo(componentBackupDir); } @@ -73,7 +75,7 @@ public void Remove() #endif private void LoadInfFileInformation(IFileInfo infFile) { - StaticViewModel.AddDebugMessage($"Processing inf file {infFile.FullName}"); + _logger.Debug($"Processing inf file {infFile.FullName}"); using (StreamReader reader = new StreamReader(infFile.OpenRead())) { @@ -94,7 +96,7 @@ private void LoadInfFileInformation(IFileInfo infFile) line.StartsWith("AMDOCLName", StringComparison.OrdinalIgnoreCase) || line.StartsWith("AMDWINName", StringComparison.OrdinalIgnoreCase)) { - StaticViewModel.AddDebugMessage($"Attempting to obtain inf file description from {line}"); + _logger.Debug($"Attempting to obtain inf file description from {line}"); Description = line.Substring(line.IndexOf("\"", StringComparison.OrdinalIgnoreCase)).Trim('\"'); return; } diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/InstallerFilesModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/InstallerFilesModel.cs similarity index 78% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/InstallerFilesModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/InstallerFilesModel.cs index 24d1cdf..f76484d 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/InstallerFilesModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/InstallerFilesModel.cs @@ -3,18 +3,17 @@ using System.Diagnostics; using System.IO; using System.IO.Abstractions; -#if NET48 using System.Linq; -#endif using System.Reflection; -using RadeonSoftwareSlimmer.Services; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { public class InstallerFilesModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; private readonly IFileSystem _fileSystem; + private readonly IProcessRunner _processRunner; private string _installerFile; private string _extractedInstallerDirectory; #if NET6_0_OR_GREATER @@ -25,9 +24,11 @@ public class InstallerFilesModel : INotifyPropertyChanged #endif - public InstallerFilesModel(IFileSystem fileSystem) + public InstallerFilesModel(IFileSystem fileSystem, IProcessRunner processRunner, IAppLogger logger) { + _logger = logger; _fileSystem = fileSystem; + _processRunner = processRunner; } @@ -58,8 +59,7 @@ public string ExtractedInstallerDirectory public void ExtractInstallerFiles() { string sevenZipExe = _fileSystem.Path.Combine(_fileSystem.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7-Zip", "7z.exe"); - ProcessHandler processHandler = new ProcessHandler(sevenZipExe); - int exitCode = processHandler.RunProcess($"x \"{InstallerFile}\" -o\"{ExtractedInstallerDirectory}\""); + int exitCode = _processRunner.RunProcess(sevenZipExe, $"x \"{InstallerFile}\" -o\"{ExtractedInstallerDirectory}\""); //https://sevenzip.osdn.jp/chm/cmdline/exit_codes.htm //Add messages for each possibility? @@ -93,7 +93,7 @@ public bool ValidateInstallerFile() { if (string.IsNullOrWhiteSpace(_installerFile)) { - StaticViewModel.AddLogMessage("Please provide an installer file"); + _logger.Info("Please provide an installer file"); return false; } @@ -103,24 +103,24 @@ public bool ValidateInstallerFile() if (Array.Exists(_fileSystem.Path.GetInvalidPathChars(), c => fileInfo.DirectoryName.Contains(c))) { - StaticViewModel.AddLogMessage("File directory contains invalid characters"); + _logger.Info("File directory contains invalid characters"); return false; } if (Array.Exists(_fileSystem.Path.GetInvalidFileNameChars(), (c => fileInfo.Name.Contains(c)))) { - StaticViewModel.AddLogMessage("File name contains invalid characters"); + _logger.Info("File name contains invalid characters"); return false; } if (!fileInfo.Exists) { - StaticViewModel.AddLogMessage($"Installer file {_installerFile} does not exist or cannot be accessed"); + _logger.Info($"Installer file {_installerFile} does not exist or cannot be accessed"); return false; } } catch (Exception ex) { // FileInfo.New validates the directory path - StaticViewModel.AddLogMessage(ex); + _logger.Info(ex); return false; } @@ -131,7 +131,7 @@ public bool ValidatePreExtractLocation() { if (string.IsNullOrWhiteSpace(_extractedInstallerDirectory)) { - StaticViewModel.AddLogMessage($"Please enter an extraction path"); + _logger.Info("Please enter an extraction path"); return false; } try @@ -140,28 +140,28 @@ public bool ValidatePreExtractLocation() if (Array.Exists(_fileSystem.Path.GetInvalidPathChars(), c => directoryInfo.FullName.Contains(c))) { - StaticViewModel.AddLogMessage("Directory contains invalid characters"); + _logger.Info("Directory contains invalid characters"); return false; } #if NET6_0_OR_GREATER if (Array.Exists(extraInvalidDirChars, c => directoryInfo.FullName.Contains(c))) { - StaticViewModel.AddLogMessage("Directory contains invalid characters"); + _logger.Info("Directory contains invalid characters"); return false; } #endif if (directoryInfo.Exists && (directoryInfo.GetDirectories().Length > 0 || directoryInfo.GetFiles().Length > 0)) { - StaticViewModel.AddLogMessage($"Extraction folder {_extractedInstallerDirectory} is not empty"); + _logger.Info($"Extraction folder {_extractedInstallerDirectory} is not empty"); return false; } } catch (Exception ex) { // DirectoryInfo.New validates the path - StaticViewModel.AddLogMessage(ex); + _logger.Info(ex); return false; } @@ -172,7 +172,7 @@ public bool ValidateExtractedLocation() { if (string.IsNullOrWhiteSpace(_extractedInstallerDirectory)) { - StaticViewModel.AddLogMessage($"Please enter an extraction path"); + _logger.Info("Please enter an extraction path"); return false; } @@ -182,14 +182,14 @@ public bool ValidateExtractedLocation() if (Array.Exists(_fileSystem.Path.GetInvalidPathChars(), c => directoryInfo.FullName.Contains(c))) { - StaticViewModel.AddLogMessage("Directory contains invalid characters"); + _logger.Info("Directory contains invalid characters"); return false; } #if NET6_0_OR_GREATER if (Array.Exists(extraInvalidDirChars, c => directoryInfo.FullName.Contains(c))) { - StaticViewModel.AddLogMessage("Directory contains invalid characters"); + _logger.Info("Directory contains invalid characters"); return false; } #endif @@ -204,14 +204,14 @@ public bool ValidateExtractedLocation() } else { - StaticViewModel.AddLogMessage($"Expected installer files not found in {_extractedInstallerDirectory}"); + _logger.Info($"Expected installer files not found in {_extractedInstallerDirectory}"); return false; } } catch (Exception ex) { // DirectoryInfo.New validates the path - StaticViewModel.AddLogMessage(ex); + _logger.Info(ex); return false; } } diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/PackageListModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/PackageListModel.cs similarity index 87% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/PackageListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/PackageListModel.cs index 6dc8db0..c9fe295 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/PackageListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/PackageListModel.cs @@ -6,12 +6,13 @@ using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { public class PackageListModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; private readonly IFileSystem _fileSystem; private IEnumerable _packages; private IDirectoryInfo _installDir; @@ -23,8 +24,9 @@ public class PackageListModel : INotifyPropertyChanged }; - public PackageListModel(IFileSystem fileSystem) + public PackageListModel(IFileSystem fileSystem, IAppLogger logger) { + _logger = logger; _fileSystem = fileSystem; } @@ -56,14 +58,14 @@ public void LoadOrRefresh(IDirectoryInfo installDirectory) } } - public static void RemovePackage(PackageModel packageToRemove) + public void RemovePackage(PackageModel packageToRemove) { if (packageToRemove == null) throw new ArgumentNullException(nameof(packageToRemove)); JObject fullJson; - StaticViewModel.AddDebugMessage($"Removing package {packageToRemove.ProductName} from {packageToRemove.GetFile().FullName}"); + _logger.Debug($"Removing package {packageToRemove.ProductName} from {packageToRemove.GetFile().FullName}"); using (StreamReader streamReader = new StreamReader(packageToRemove.GetFile().OpenRead())) using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader)) @@ -108,13 +110,13 @@ public void RestoreToDefault() } else { - StaticViewModel.AddDebugMessage($"Attempted to restore package file {backupFile.FullName} from default, but no backup directory found."); + _logger.Debug($"Attempted to restore package file {backupFile.FullName} from default, but no backup directory found."); } } } else { - StaticViewModel.AddDebugMessage("Attempted to restore packages from default, but no backup directory found."); + _logger.Debug("Attempted to restore packages from default, but no backup directory found."); } } @@ -139,7 +141,7 @@ private IEnumerable GetAllInstallerPackages() package.Url = token.SelectToken("Info.url").ToString(); package.Type = token.SelectToken("Info.ptype").ToString(); - StaticViewModel.AddDebugMessage($"Found package {package.ProductName} in {package.GetFile().FullName}"); + _logger.Debug($"Found package {package.ProductName} in {package.GetFile().FullName}"); yield return package; } } @@ -158,7 +160,7 @@ private void BackupIfNotAlready() _fileSystem.Directory.CreateDirectory(backupFile.DirectoryName); IFileInfo sourceFile = _fileSystem.FileInfo.New(_fileSystem.Path.Combine(_installDir.FullName, packageFile)); - StaticViewModel.AddDebugMessage($"Backing up {sourceFile.FullName} to {backupFile.FullName}"); + _logger.Debug($"Backing up {sourceFile.FullName} to {backupFile.FullName}"); _fileSystem.File.Copy(sourceFile.FullName, backupFile.FullName); } } diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/PackageModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/PackageModel.cs similarity index 96% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/PackageModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/PackageModel.cs index a1e168d..403cc05 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/PackageModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/PackageModel.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.IO.Abstractions; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { public class PackageModel : INotifyPropertyChanged { diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/ScheduledTaskXmlListModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/ScheduledTaskXmlListModel.cs similarity index 90% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/ScheduledTaskXmlListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/ScheduledTaskXmlListModel.cs index da8ef06..f688698 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/ScheduledTaskXmlListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/ScheduledTaskXmlListModel.cs @@ -6,19 +6,21 @@ using System.Linq; using System.Xml; using System.Xml.Linq; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { //So many problems with these files... This is why we can't have nice things. public class ScheduledTaskXmlListModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; private readonly IFileSystem _fileSystem; private IEnumerable _scheduledTasks; - public ScheduledTaskXmlListModel(IFileSystem fileSystem) + public ScheduledTaskXmlListModel(IFileSystem fileSystem, IAppLogger logger) { + _logger = logger; _fileSystem = fileSystem; } @@ -65,7 +67,7 @@ public void RestoreToDefault() { if (_scheduledTasks != null) { - StaticViewModel.AddDebugMessage("Restoring scheduled tasks to enabled"); + _logger.Debug("Restoring scheduled tasks to enabled"); foreach (ScheduledTaskXmlModel scheduledTask in _scheduledTasks) { @@ -99,7 +101,7 @@ private IEnumerable GetInstallerScheduledTasks(IDirectory string arguments = xDoc.Root.Element(xNs + "Actions").Element(xNs + "Exec").Element(xNs + "Arguments").Value; scheduledTask.Command = $"{command} {arguments}"; - StaticViewModel.AddDebugMessage($"Found scheduled task {scheduledTask.Description} in {file.FullName}"); + _logger.Debug($"Found scheduled task {scheduledTask.Description} in {file.FullName}"); yield return scheduledTask; } } @@ -124,7 +126,7 @@ private bool TryGetScheduledTaskXDocument(IFileInfo file, FileAccess fileAccess, //Some files have incorrect encoding :( //This happens even with legit exported files from Windows itself //https://stackoverflow.com/questions/29915467/there-is-no-unicode-byte-order-mark-cannot-switch-to-unicode - StaticViewModel.AddDebugMessage($"Wrong encoding for {file.FullName}"); + _logger.Debug($"Wrong encoding for {file.FullName}"); try { @@ -132,7 +134,7 @@ private bool TryGetScheduledTaskXDocument(IFileInfo file, FileAccess fileAccess, } catch (XmlException ex) { - StaticViewModel.AddDebugMessage(ex); + _logger.Error(ex); return false; } } diff --git a/src/RadeonSoftwareSlimmer/Models/PreInstall/ScheduledTaskXmlModel.cs b/src/RadeonSoftwareSlimmer.Core/PreInstall/ScheduledTaskXmlModel.cs similarity index 95% rename from src/RadeonSoftwareSlimmer/Models/PreInstall/ScheduledTaskXmlModel.cs rename to src/RadeonSoftwareSlimmer.Core/PreInstall/ScheduledTaskXmlModel.cs index 31046a8..b93f866 100644 --- a/src/RadeonSoftwareSlimmer/Models/PreInstall/ScheduledTaskXmlModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PreInstall/ScheduledTaskXmlModel.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.IO.Abstractions; -namespace RadeonSoftwareSlimmer.Models.PreInstall +namespace RadeonSoftwareSlimmer.Core.PreInstall { public class ScheduledTaskXmlModel : INotifyPropertyChanged { diff --git a/src/RadeonSoftwareSlimmer.Core/RadeonSoftwareSlimmer.Core.csproj b/src/RadeonSoftwareSlimmer.Core/RadeonSoftwareSlimmer.Core.csproj new file mode 100644 index 0000000..a6d20aa --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/RadeonSoftwareSlimmer.Core.csproj @@ -0,0 +1,17 @@ + + + netstandard2.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs b/src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs new file mode 100644 index 0000000..f760eb4 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics; +using System.Threading; +using RadeonSoftwareSlimmer.Core.Interfaces; + +namespace RadeonSoftwareSlimmer.Core.Services +{ + public class ProcessHandler : IProcessHandler + { + private readonly IAppLogger _logger; + private readonly string _processName; + + + public ProcessHandler(string processName, IAppLogger logger) + { + _logger = logger; + _processName = processName; + } + + + public bool IsProcessRunning() + { + if (string.IsNullOrWhiteSpace(_processName)) + return false; + + return Process.GetProcessesByName(_processName).Length > 0; + } + + public void WaitForProcessToEnd(int maxWaitSeconds) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + while (IsProcessRunning()) + { + if (sw.ElapsedMilliseconds >= maxWaitSeconds * 1000) + { + foreach (Process process in Process.GetProcessesByName(_processName)) + { + try + { + process.Kill(); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to stop process [{process.Id}] {process.ProcessName}"); + } + } + } + + Thread.Sleep(1000); + } + } + + public void WaitForProcessToStart(int maxWaitSeconds) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + while (!IsProcessRunning()) + { + if (sw.ElapsedMilliseconds >= maxWaitSeconds * 1000) + { + _logger.Debug($"Process {_processName} did not start"); + return; + } + + Thread.Sleep(1000); + } + } + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs b/src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs new file mode 100644 index 0000000..cf21d9d --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using System.IO.Abstractions; +using RadeonSoftwareSlimmer.Core.Interfaces; + +namespace RadeonSoftwareSlimmer.Core.Services +{ + public class ProcessRunner : IProcessRunner + { + private readonly IAppLogger _logger; + + private readonly IFileSystem _fileSystem; + + + public ProcessRunner(IFileSystem fileSystem, IAppLogger logger) + { + _logger = logger; + _fileSystem = fileSystem; + } + + + public int RunProcess(string fileName, string arguments) + { + IFileInfo file = _fileSystem.FileInfo.New(fileName); + if (!file.Exists) + { + _logger.Debug($"{file.FullName} does not exist or user does not have access"); + return -1; + } + + using (Process process = new Process()) + { + process.StartInfo.FileName = file.FullName; + process.StartInfo.Arguments = arguments; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + + _logger.Debug($"Running {process.StartInfo.FileName} {process.StartInfo.Arguments}"); + process.Start(); + process.WaitForExit(); + _logger.Debug($"Process finished with ExitCode: {process.ExitCode}"); + _logger.Debug($"StandardOutput: {process.StandardOutput.ReadToEnd()}"); + _logger.Debug($"StandardError: {process.StandardError.ReadToEnd()}"); + + return process.ExitCode; + } + } + } +} diff --git a/src/RadeonSoftwareSlimmer.Windows/RadeonSoftwareSlimmer.Windows.csproj b/src/RadeonSoftwareSlimmer.Windows/RadeonSoftwareSlimmer.Windows.csproj new file mode 100644 index 0000000..5cb55e0 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Windows/RadeonSoftwareSlimmer.Windows.csproj @@ -0,0 +1,23 @@ + + + netstandard2.0 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + \ No newline at end of file diff --git a/src/RadeonSoftwareSlimmer/Services/WindowsRegistry.cs b/src/RadeonSoftwareSlimmer.Windows/WindowsRegistry.cs similarity index 83% rename from src/RadeonSoftwareSlimmer/Services/WindowsRegistry.cs rename to src/RadeonSoftwareSlimmer.Windows/WindowsRegistry.cs index 6524f67..856ac98 100644 --- a/src/RadeonSoftwareSlimmer/Services/WindowsRegistry.cs +++ b/src/RadeonSoftwareSlimmer.Windows/WindowsRegistry.cs @@ -1,7 +1,7 @@ using Microsoft.Win32; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Services +namespace RadeonSoftwareSlimmer.Windows { public class WindowsRegistry : IRegistry { diff --git a/src/RadeonSoftwareSlimmer/Services/WindowsRegistryKey.cs b/src/RadeonSoftwareSlimmer.Windows/WindowsRegistryKey.cs similarity index 86% rename from src/RadeonSoftwareSlimmer/Services/WindowsRegistryKey.cs rename to src/RadeonSoftwareSlimmer.Windows/WindowsRegistryKey.cs index a755908..e85310f 100644 --- a/src/RadeonSoftwareSlimmer/Services/WindowsRegistryKey.cs +++ b/src/RadeonSoftwareSlimmer.Windows/WindowsRegistryKey.cs @@ -1,8 +1,8 @@ using System; using Microsoft.Win32; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Services +namespace RadeonSoftwareSlimmer.Windows { public class WindowsRegistryKey : IRegistryKey { @@ -32,9 +32,9 @@ public object GetValue(string name, object defaultValue) return _regKey.GetValue(name, defaultValue); } - public void SetValue(string name, object value, RegistryValueKind valueKind) + public void SetValue(string name, object value, RadeonSoftwareSlimmer.Core.Enums.RegistryValueKind valueKind) { - _regKey.SetValue(name, value, valueKind); + _regKey.SetValue(name, value, (Microsoft.Win32.RegistryValueKind)valueKind); } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs b/src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs index 7c97491..08b9834 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs +++ b/src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO.Abstractions; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Interfaces; using RadeonSoftwareSlimmer.Services; using RadeonSoftwareSlimmer.ViewModels; @@ -209,10 +209,7 @@ private bool IsValidRadeonSoftwareDirectory(string directory) return false; string cliFile = _fileSystem.Path.Combine(directory, RADEON_SOFTWARE_CLI_FILE_NAME); - if (!_fileSystem.File.Exists(cliFile)) - return false; - - return true; + return _fileSystem.File.Exists(cliFile); } catch (Exception ex) { diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs b/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs index 06698c0..1ad038a 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs +++ b/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using RadeonSoftwareSlimmer.Intefaces; using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; namespace RadeonSoftwareSlimmer.Models.PostInstall { diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs b/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs index 9c2c8eb..d4cba91 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs +++ b/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel; using System.Globalization; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Interfaces; using RadeonSoftwareSlimmer.Services; using RadeonSoftwareSlimmer.ViewModels; diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs b/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs index e4057bb..3e130c0 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs +++ b/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.ComponentModel; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Interfaces; using RadeonSoftwareSlimmer.ViewModels; namespace RadeonSoftwareSlimmer.Models.PostInstall diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs b/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs index 1eb038d..6b7b47a 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs +++ b/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs @@ -1,7 +1,8 @@ using System; using System.ComponentModel; using System.ServiceProcess; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Enums; +using RadeonSoftwareSlimmer.Core.Interfaces; using RadeonSoftwareSlimmer.Services; using RadeonSoftwareSlimmer.ViewModels; @@ -319,7 +320,7 @@ private void SaveOriginalStartMode() using (IRegistryKey serviceKey = _registry.LocalMachine.OpenSubKey(SERVICES_REG_KEY + Name, true)) { object currentStartMode = serviceKey.GetValue(SERVICE_START_VALUE_NAME); - serviceKey.SetValue(SERVICE_ORIGINAL_START_VALUE_NAME, currentStartMode, Microsoft.Win32.RegistryValueKind.DWord); + serviceKey.SetValue(SERVICE_ORIGINAL_START_VALUE_NAME, currentStartMode, RegistryValueKind.DWord); } } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs b/src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs index 13c6731..7387f42 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs +++ b/src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs @@ -1,7 +1,7 @@ using System; using System.ComponentModel; -using Microsoft.Win32; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Enums; +using RadeonSoftwareSlimmer.Core.Interfaces; namespace RadeonSoftwareSlimmer.Models.PostInstall { diff --git a/src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj b/src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj index 365b90f..27e9fc1 100644 --- a/src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj +++ b/src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj @@ -1,46 +1,42 @@ - WinExe + net10.0-windows;net9.0-windows;net8.0-windows;net48 + win-x64 true true - - Radeon Software Slimmer RadeonSoftwareSlimmer.App - Radeon Software Slimmer - Greg Seaton icon.ico app.manifest - - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + - \ No newline at end of file diff --git a/src/RadeonSoftwareSlimmer/Services/ProcessHandler.cs b/src/RadeonSoftwareSlimmer/Services/ProcessHandler.cs deleted file mode 100644 index d22cb53..0000000 --- a/src/RadeonSoftwareSlimmer/Services/ProcessHandler.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO.Abstractions; -using System.Threading; -using RadeonSoftwareSlimmer.ViewModels; - -namespace RadeonSoftwareSlimmer.Services -{ - public class ProcessHandler - { - private readonly IFileInfo _file; - private readonly string _fileNameWithoutExtension; - - - public ProcessHandler(string fileName) : this(fileName, new FileSystem()) { } - - public ProcessHandler(string fileName, IFileSystem fileSystem) - { - if (string.IsNullOrWhiteSpace(fileName)) - throw new ArgumentNullException($"{fileName} is null or empty"); - - _file = fileSystem.FileInfo.New(fileName); - _fileNameWithoutExtension = _file.Name.Substring(0, _file.Name.Length - _file.Extension.Length); - } - - - public int RunProcess() - { - return RunProcess(string.Empty); - } - - public int RunProcess(string arguments) - { - if (!_file.Exists) - { - StaticViewModel.AddDebugMessage($"{_file.FullName} does not exist or user does not have access"); - return -1; - } - - using (Process process = new Process()) - { - process.StartInfo.FileName = _file.FullName; - process.StartInfo.Arguments = arguments; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardError = true; - - StaticViewModel.AddDebugMessage($"Running {process.StartInfo.FileName} {process.StartInfo.Arguments}"); - process.Start(); - process.WaitForExit(); - StaticViewModel.AddDebugMessage($"Process finished with ExitCode: {process.ExitCode}"); - StaticViewModel.AddDebugMessage($"StandardOutput: {process.StandardOutput.ReadToEnd()}"); - StaticViewModel.AddDebugMessage($"StandardError: {process.StandardError.ReadToEnd()}"); - - return process.ExitCode; - } - } - - public bool IsProcessRunning() - { - if (!_file.Exists) - return false; - - if (Process.GetProcessesByName(_fileNameWithoutExtension).Length > 0) - return true; - else - return false; - } - - public void WaitForProcessToEnd(int maxWaitSeconds) - { - if (!_file.Exists) - return; - - Stopwatch sw = new Stopwatch(); - sw.Start(); - - while (IsProcessRunning()) - { - if (sw.ElapsedMilliseconds >= maxWaitSeconds * 1000) - { - foreach (Process process in Process.GetProcessesByName(_fileNameWithoutExtension)) - { - try - { - process.Kill(); - } - catch (Exception ex) - { - StaticViewModel.AddDebugMessage(ex, $"Unable to stop process [{process.Id}] {process.ProcessName}"); - } - } - } - - Thread.Sleep(1000); - } - } - - public void WaitForProcessToStart(int maxWaitSeconds) - { - if (!_file.Exists) - return; - - Stopwatch sw = new Stopwatch(); - sw.Start(); - - while (!IsProcessRunning()) - { - if (sw.ElapsedMilliseconds >= maxWaitSeconds * 1000) - { - StaticViewModel.AddDebugMessage($"Process {_file.Name} did not start"); - return; - } - - Thread.Sleep(1000); - } - } - } -} diff --git a/src/RadeonSoftwareSlimmer/Services/ThemeService.cs b/src/RadeonSoftwareSlimmer/Services/ThemeService.cs index 5b0d4b2..2aa6f1f 100644 --- a/src/RadeonSoftwareSlimmer/Services/ThemeService.cs +++ b/src/RadeonSoftwareSlimmer/Services/ThemeService.cs @@ -1,6 +1,6 @@ using System.Windows; using ControlzEx.Theming; -using RadeonSoftwareSlimmer.Intefaces; +using RadeonSoftwareSlimmer.Core.Interfaces; namespace RadeonSoftwareSlimmer.Services { diff --git a/src/Shared/Shared.shproj b/src/Shared/Shared.shproj index a4a27e4..0ce052c 100644 --- a/src/Shared/Shared.shproj +++ b/src/Shared/Shared.shproj @@ -1,4 +1,3 @@ - 9b80e4b0-8113-4fd6-a3b2-f67e98604f6c diff --git a/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj b/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj new file mode 100644 index 0000000..fd3c690 --- /dev/null +++ b/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj @@ -0,0 +1,41 @@ + + + net10.0 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + PreserveNewest + + + + $(MSBuildProjectDirectory)\$(MSBuildProjectName).runsettings + trx%3bLogFileName=$(MSBuildProjectName)_$(TargetFramework).trx + + \ No newline at end of file diff --git a/test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj b/test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj index db21f30..1f471e7 100644 --- a/test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj +++ b/test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj @@ -1,47 +1,42 @@ - - Library + net10.0-windows;net9.0-windows;net8.0-windows;net48 + win-x64 - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - PreserveNewest - $(MSBuildProjectDirectory)\$(MSBuildProjectName).runsettings trx%3bLogFileName=$(MSBuildProjectName)_$(TargetFramework).trx - - + \ No newline at end of file diff --git a/test/RadeonSoftwareSlimmer.Windows.Test/RadeonSoftwareSlimmer.Windows.Test.csproj b/test/RadeonSoftwareSlimmer.Windows.Test/RadeonSoftwareSlimmer.Windows.Test.csproj new file mode 100644 index 0000000..4fe20b0 --- /dev/null +++ b/test/RadeonSoftwareSlimmer.Windows.Test/RadeonSoftwareSlimmer.Windows.Test.csproj @@ -0,0 +1,42 @@ + + + net10.0-windows;net9.0-windows;net8.0-windows;net48 + win-x64 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + PreserveNewest + + + + $(MSBuildProjectDirectory)\$(MSBuildProjectName).runsettings + trx%3bLogFileName=$(MSBuildProjectName)_$(TargetFramework).trx + + \ No newline at end of file From 76ebc092a83808ee3ddf4da234c30603237edcad Mon Sep 17 00:00:00 2001 From: Greg Seaton Date: Mon, 27 Apr 2026 01:15:54 -0400 Subject: [PATCH 3/4] commit current progress --- .editorconfig | 3 + .vscode/settings.json | 4 ++ .../Enums/TaskState.cs | 12 ++++ .../Interfaces/IAppLogger.cs | 5 ++ .../Interfaces/IProcessHandler.cs | 6 +- .../Interfaces/IScheduledTask.cs | 22 +++++++ .../Interfaces/IScheduledTaskService.cs | 12 ++++ .../PostInstall/HostServiceModel.cs | 65 +++++++++---------- .../PostInstall/InstalledListModel.cs | 15 +++-- .../PostInstall/InstalledModel.cs | 38 +++++------ .../PostInstall/RunningHostServiceModel.cs | 2 +- .../PostInstall/RunningProcessModel.cs | 2 +- .../PostInstall/ScheduledTaskListModel.cs | 25 ++++--- .../PostInstall/ScheduledTaskModel.cs | 52 ++++++++------- .../PostInstall/ServiceListModel.cs | 11 ++-- .../PostInstall/ServiceModel.cs | 61 +++++++++-------- .../PostInstall/TempFileListModel.cs | 14 ++-- .../PostInstall/TempFileModel.cs | 16 +++-- .../PostInstall/WindowsAppStartupModel.cs | 16 ++--- .../ProcessHandler.cs | 24 ++++--- .../ProcessRunner.cs | 2 +- 21 files changed, 236 insertions(+), 171 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/RadeonSoftwareSlimmer.Core/Enums/TaskState.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTask.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTaskService.cs rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/HostServiceModel.cs (67%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/InstalledListModel.cs (87%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/InstalledModel.cs (71%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/RunningHostServiceModel.cs (82%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/RunningProcessModel.cs (97%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/ScheduledTaskListModel.cs (71%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/ScheduledTaskModel.cs (57%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/ServiceListModel.cs (91%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/ServiceModel.cs (80%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/TempFileListModel.cs (93%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/TempFileModel.cs (85%) rename src/{RadeonSoftwareSlimmer/Models => RadeonSoftwareSlimmer.Core}/PostInstall/WindowsAppStartupModel.cs (83%) rename src/{RadeonSoftwareSlimmer.Core/Services => RadeonSoftwareSlimmer.Windows}/ProcessHandler.cs (66%) rename src/{RadeonSoftwareSlimmer.Core/Services => RadeonSoftwareSlimmer.Windows}/ProcessRunner.cs (97%) diff --git a/.editorconfig b/.editorconfig index 8663a29..9b96009 100644 --- a/.editorconfig +++ b/.editorconfig @@ -40,6 +40,9 @@ dotnet_diagnostic.IDE0031.severity = none # Not available in .NET 4.8 dotnet_diagnostic.CA1510.severity = none +# IDE0011: Add braces +dotnet_diagnostic.IDE0011.severity = none + # ******************************************************************************************* # SonarAnalyzer Rules # S3897: Classes that provide "Equals()" should implement "IEquatable" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fb38bbe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true +} diff --git a/src/RadeonSoftwareSlimmer.Core/Enums/TaskState.cs b/src/RadeonSoftwareSlimmer.Core/Enums/TaskState.cs new file mode 100644 index 0000000..e859006 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Enums/TaskState.cs @@ -0,0 +1,12 @@ +namespace RadeonSoftwareSlimmer.Core.Enums +{ + // https://dahall.github.io/TaskScheduler/html/T_Microsoft_Win32_TaskScheduler_TaskState.htm + public enum TaskState : int + { + Unknown = 0, + Disabled = 1, + Queued = 2, + Ready = 3, + Running = 4 + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs index ee2fd46..f2438bd 100644 --- a/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IAppLogger.cs @@ -1,14 +1,19 @@ using System; +using System.Runtime.CompilerServices; namespace RadeonSoftwareSlimmer.Core.Interfaces { public interface IAppLogger { + bool IsLoading { get; set; } + void Info(string message); void Info(Exception ex); + void Info(Exception ex, string message); void Debug(string message); void Debug(Exception ex); + void Debug(Exception ex, string message); void Error(Exception ex); void Error(Exception ex, string message); diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs index caeee92..f41e984 100644 --- a/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IProcessHandler.cs @@ -2,10 +2,10 @@ { public interface IProcessHandler { - bool IsProcessRunning(); + bool IsProcessRunning(string processName); - void WaitForProcessToEnd(int maxWaitSeconds); + void WaitForProcessToEnd(string processName, int maxWaitSeconds); - void WaitForProcessToStart(int maxWaitSeconds); + void WaitForProcessToStart(string processName, int maxWaitSeconds); } } diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTask.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTask.cs new file mode 100644 index 0000000..18d5b5d --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTask.cs @@ -0,0 +1,22 @@ +using System; +using RadeonSoftwareSlimmer.Core.Enums; + +namespace RadeonSoftwareSlimmer.Core.Interfaces +{ + // https://dahall.github.io/TaskScheduler/html/T_Microsoft_Win32_TaskScheduler_Task.htm + public interface IScheduledTask : IDisposable + { + string Name { get; set; } + string Description { get; set; } + bool Enabled { get; set; } + bool IsActive { get; set; } + TaskState State { get; set; } + string Command { get; set; } + DateTime LastRunTime { get; set; } + string Author { get; set; } + + void RegisterChanges(); + + void Stop(); + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTaskService.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTaskService.cs new file mode 100644 index 0000000..5ac2903 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IScheduledTaskService.cs @@ -0,0 +1,12 @@ +using System; + +namespace RadeonSoftwareSlimmer.Core.Interfaces +{ + // https://dahall.github.io/TaskScheduler/html/T_Microsoft_Win32_TaskScheduler_TaskService.htm + public interface IScheduledTaskService + { + IScheduledTask GetTask(string taskName); + + IScheduledTask[] FindAllTasks(Predicate filter, bool searchAllFolders = true); + } +} diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/HostServiceModel.cs similarity index 67% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/HostServiceModel.cs index 08b9834..03a3d3b 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/HostServiceModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/HostServiceModel.cs @@ -3,15 +3,16 @@ using System.ComponentModel; using System.IO.Abstractions; using RadeonSoftwareSlimmer.Core.Interfaces; -using RadeonSoftwareSlimmer.Services; -using RadeonSoftwareSlimmer.ViewModels; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class HostServiceModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; private readonly IFileSystem _fileSystem; private readonly IRegistry _registry; + private readonly IProcessHandler _processHandler; + private readonly IProcessRunner _processRunner; private IDirectoryInfo _cnDir; private bool _installed; private IList _hostServices; @@ -26,10 +27,13 @@ public class HostServiceModel : INotifyPropertyChanged public const string CNCMD_RESTART = "restart"; - public HostServiceModel(IFileSystem fileSystem, IRegistry registry) + public HostServiceModel(IFileSystem fileSystem, IRegistry registry, IAppLogger logger, IProcessHandler processHandler, IProcessRunner processRunner) { + _logger = logger; _fileSystem = fileSystem; _registry = registry; + _processHandler = processHandler; + _processRunner = processRunner; Installed = false; } @@ -71,27 +75,25 @@ public void StopRadeonSoftware() { try { - StaticViewModel.AddLogMessage("Stopping Radeon Software Host Services"); - StaticViewModel.IsLoading = true; + _logger.Info("Stopping Radeon Software Host Services"); + _logger.IsLoading = true; RadeonSoftwareCli(CNCMD_EXIT); //The command to stop the services does not wait for them to fully end - ProcessHandler hostProcess = new ProcessHandler(_fileSystem.Path.Combine(_cnDir.FullName, "AMDRSServ.exe")); - hostProcess.WaitForProcessToEnd(30); - ProcessHandler radeonSoftwareProcess = new ProcessHandler(_fileSystem.Path.Combine(_cnDir.FullName, "RadeonSoftware.exe")); - radeonSoftwareProcess.WaitForProcessToEnd(30); + _processHandler.WaitForProcessToEnd("AMDRSServ", 30); + _processHandler.WaitForProcessToEnd("RadeonSoftware", 30); - StaticViewModel.AddLogMessage("Stopped Radeon Software Host Services"); + _logger.Info("Stopped Radeon Software Host Services"); } catch (Exception ex) { - StaticViewModel.AddLogMessage(ex, "Failed to stop Radeon Software Host Services"); + _logger.Info(ex, "Failed to stop Radeon Software Host Services"); } finally { LoadOrRefresh(); - StaticViewModel.IsLoading = false; + _logger.IsLoading = false; } } } @@ -102,26 +104,25 @@ public void RestartRadeonSoftware() { try { - StaticViewModel.AddLogMessage("Restarting Radeon Software Host Services"); - StaticViewModel.IsLoading = true; + _logger.Info("Restarting Radeon Software Host Services"); + _logger.IsLoading = true; RadeonSoftwareCli(CNCMD_RESTART); //Wait for services to start back up - ProcessHandler radeonSoftwareProcess = new ProcessHandler(_fileSystem.Path.Combine(_cnDir.FullName, "RadeonSoftware.exe")); - radeonSoftwareProcess.WaitForProcessToStart(30); + _processHandler.WaitForProcessToStart("RadeonSoftware", 30); - StaticViewModel.AddLogMessage("Restarted Radeon Software Host Services"); + _logger.Info("Restarted Radeon Software Host Services"); } catch (Exception ex) { - StaticViewModel.AddLogMessage(ex, "Failed to restart Radeon Software Host Services"); + _logger.Info(ex, "Failed to restart Radeon Software Host Services"); } finally { LoadOrRefresh(); - StaticViewModel.IsLoading = false; + _logger.IsLoading = false; } } } @@ -146,25 +147,25 @@ private void LoadCnDirectory() string registryDirectory = GetInstallDirectoryFromRegistry(); if (IsValidRadeonSoftwareDirectory(registryDirectory)) { - StaticViewModel.AddDebugMessage($"Found Radeon Software installation directory at {registryDirectory}"); + _logger.Debug($"Found Radeon Software installation directory at {registryDirectory}"); _cnDir = _fileSystem.DirectoryInfo.New(registryDirectory); Installed = true; } else { // Then check the default location - StaticViewModel.AddDebugMessage("Unable to determine Radeon Software installation directory from registry. Checking default location."); + _logger.Debug("Unable to determine Radeon Software installation directory from registry. Checking default location."); string defaultDirectory = _fileSystem.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "AMD", "CNext", "CNext"); if (IsValidRadeonSoftwareDirectory(defaultDirectory)) { - StaticViewModel.AddDebugMessage($"Found Radeon Software installation directory at {defaultDirectory}"); + _logger.Debug($"Found Radeon Software installation directory at {defaultDirectory}"); _cnDir = _fileSystem.DirectoryInfo.New(defaultDirectory); Installed = true; } else { Installed = false; - StaticViewModel.AddDebugMessage("Unable to determine Radeon Software installation directory from default location. Assuming it is not installed."); + _logger.Debug("Unable to determine Radeon Software installation directory from default location. Assuming it is not installed."); } } } @@ -177,14 +178,14 @@ private string GetInstallDirectoryFromRegistry() { if (cnKey == null) { - StaticViewModel.AddDebugMessage($"Unable to open registry key {INSTALL_FOLDER_REGISTRY_KEY}."); + _logger.Debug($"Unable to open registry key {INSTALL_FOLDER_REGISTRY_KEY}."); return string.Empty; } object installDirObj = cnKey.GetValue(INSTALL_FOLDER_REGISTRY_VALUE_NAME); if (installDirObj == null) { - StaticViewModel.AddDebugMessage($"Registry value {INSTALL_FOLDER_REGISTRY_VALUE_NAME} does not exist or is null."); + _logger.Debug($"Registry value {INSTALL_FOLDER_REGISTRY_VALUE_NAME} does not exist or is null."); return string.Empty; } @@ -193,7 +194,7 @@ private string GetInstallDirectoryFromRegistry() } catch (Exception ex) { - StaticViewModel.AddDebugMessage(ex); + _logger.Debug(ex); return string.Empty; } } @@ -213,19 +214,15 @@ private bool IsValidRadeonSoftwareDirectory(string directory) } catch (Exception ex) { - StaticViewModel.AddDebugMessage(ex); + _logger.Debug(ex); return false; } } - private void RadeonSoftwareCli(string arugument) + private void RadeonSoftwareCli(string aruguments) { if (_installed) - { - string cli = _fileSystem.Path.Combine(_cnDir.FullName, RADEON_SOFTWARE_CLI_FILE_NAME); - ProcessHandler processHandler = new ProcessHandler(cli); - processHandler.RunProcess(arugument); - } + _processRunner.RunProcess(_fileSystem.Path.Combine(_cnDir.FullName, RADEON_SOFTWARE_CLI_FILE_NAME), aruguments); } } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/InstalledListModel.cs similarity index 87% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/InstalledListModel.cs index 1ad038a..4895082 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/InstalledListModel.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using RadeonSoftwareSlimmer.ViewModels; using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class InstalledListModel : INotifyPropertyChanged { private readonly IRegistry _registry; + private readonly IAppLogger _logger; + private readonly IProcessRunner _processRunner; private IEnumerable _installedItems; private const string UNINSTALL_REGISTRY_PATH = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; @@ -29,9 +30,11 @@ public class InstalledListModel : INotifyPropertyChanged }; - public InstalledListModel(IRegistry registry) + public InstalledListModel(IRegistry registry, IAppLogger logger, IProcessRunner processRunner) { + _logger = logger; _registry = registry; + _processRunner = processRunner; } @@ -75,7 +78,7 @@ private IEnumerable GetAllUninstallEntries() { if (IsRadeonUninstall(uninstallKey)) { - yield return new InstalledModel(uninstallKey, uninstallName); + yield return new InstalledModel(uninstallKey, uninstallName, _logger, _processRunner); } } } @@ -91,7 +94,7 @@ private IEnumerable GetAllUninstallEntries() { if (IsRadeonUninstall(uninstallKey)) { - yield return new InstalledModel(uninstallKey, uninstallName); + yield return new InstalledModel(uninstallKey, uninstallName, _logger, _processRunner); } } } @@ -108,7 +111,7 @@ private bool IsRadeonUninstall(IRegistryKey uninstallKey) && publisher.ToString().Equals("Advanced Micro Devices, Inc.", StringComparison.OrdinalIgnoreCase) && !Array.Exists(AMD_CHIPSET_NAMES, name => displayName.ToString().Contains(name))) { - StaticViewModel.AddDebugMessage($"Found uninstall item {displayName} under {uninstallKey.Name}"); + _logger.Debug($"Found uninstall item {displayName} under {uninstallKey.Name}"); return true; } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/InstalledModel.cs similarity index 71% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/InstalledModel.cs index d4cba91..c34c9f5 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/InstalledModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/InstalledModel.cs @@ -2,20 +2,22 @@ using System.ComponentModel; using System.Globalization; using RadeonSoftwareSlimmer.Core.Interfaces; -using RadeonSoftwareSlimmer.Services; -using RadeonSoftwareSlimmer.ViewModels; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class InstalledModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; + private readonly IProcessRunner _processRunner; private bool _uninstall; private readonly bool _windowsInstaller; private string _uninstallExe; private string _uninstallArguments; - public InstalledModel(IRegistryKey uninstallKey, string keyShortName) + public InstalledModel(IRegistryKey uninstallKey, string keyShortName, IAppLogger logger, IProcessRunner processRunner) { + _logger = logger; + _processRunner = processRunner; Uninstall = false; //Again... no consistency or all the information filled out with this from AMD... @@ -57,20 +59,14 @@ public bool Uninstall public void RunUninstaller() { - if (!string.IsNullOrWhiteSpace(UninstallCommand)) - { - if (_windowsInstaller) - { - ProcessHandler processHandler = new ProcessHandler(_uninstallExe); - processHandler.RunProcess($"{_uninstallArguments} /quiet /norestart REBOOT=ReallySuppress"); - } - else - { - StaticViewModel.AddDebugMessage($"Non-Windows uninstaller for {DisplayName} not supported"); - } - } + if (string.IsNullOrWhiteSpace(UninstallCommand)) + _logger.Debug($"No uninstaller command for {DisplayName}"); + + + if (_windowsInstaller) + _processRunner.RunProcess(_uninstallExe, _uninstallArguments + "/quiet /norestart REBOOT=ReallySuppress"); else - StaticViewModel.AddDebugMessage($"No uninstaller command for {DisplayName}"); + _logger.Debug($"Non-Windows uninstaller for {DisplayName} not supported"); } @@ -95,20 +91,20 @@ private void DetermineUninstallCommand() { _uninstallArguments = $"/uninstall {productGuid:B}"; UninstallCommand = $"{_uninstallExe} {_uninstallArguments}"; - StaticViewModel.AddDebugMessage($"Detected GUID {productGuid} from {ProductCode} for {DisplayName}"); + _logger.Debug($"Detected GUID {productGuid} from {ProductCode} for {DisplayName}"); } else { - StaticViewModel.AddDebugMessage($"Unable to determine windows installer GUID from {ProductCode} for {DisplayName}"); + _logger.Debug($"Unable to determine windows installer GUID from {ProductCode} for {DisplayName}"); } } else if (!string.IsNullOrWhiteSpace(UninstallCommand)) { - StaticViewModel.AddDebugMessage($"Keeping default uninstall command {UninstallCommand} for {DisplayName}"); + _logger.Debug($"Keeping default uninstall command {UninstallCommand} for {DisplayName}"); } else { - StaticViewModel.AddDebugMessage($"Unable to determine uninstall command for {DisplayName}"); + _logger.Debug($"Unable to determine uninstall command for {DisplayName}"); } } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/RunningHostServiceModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/RunningHostServiceModel.cs similarity index 82% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/RunningHostServiceModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/RunningHostServiceModel.cs index 90bc448..4a351fb 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/RunningHostServiceModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/RunningHostServiceModel.cs @@ -1,4 +1,4 @@ -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class RunningHostServiceModel : RunningProcessModel { diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/RunningProcessModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/RunningProcessModel.cs similarity index 97% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/RunningProcessModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/RunningProcessModel.cs index 564b4f9..62e52bc 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/RunningProcessModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/RunningProcessModel.cs @@ -1,7 +1,7 @@ using System; using System.Diagnostics; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class RunningProcessModel { diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/ScheduledTaskListModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/ScheduledTaskListModel.cs similarity index 71% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/ScheduledTaskListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/ScheduledTaskListModel.cs index caf08a1..dbfc2c8 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/ScheduledTaskListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/ScheduledTaskListModel.cs @@ -1,17 +1,22 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using Microsoft.Win32.TaskScheduler; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class ScheduledTaskListModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; + private readonly IScheduledTaskService _taskService; private IEnumerable _scheduledTasks; - public ScheduledTaskListModel() { } + public ScheduledTaskListModel(IAppLogger logger, IScheduledTaskService taskService) + { + _logger = logger; + _taskService = taskService; + } public event PropertyChangedEventHandler PropertyChanged; @@ -46,17 +51,17 @@ public void ApplyChanges() } - private static IEnumerable GetAllRadeonScheduledTasks() + private IEnumerable GetAllRadeonScheduledTasks() { - foreach (Task task in TaskService.Instance.FindAllTasks(t => IsRadeonTask(t), false)) + foreach (IScheduledTask task in _taskService.FindAllTasks(t => IsRadeonTask(t), false)) { - yield return new ScheduledTaskModel(task); + yield return new ScheduledTaskModel(task, _logger, _taskService); } } - private static bool IsRadeonTask(Task scheduledTask) + private bool IsRadeonTask(IScheduledTask scheduledTask) { - string author = scheduledTask.Definition.RegistrationInfo.Author; + string author = scheduledTask.Author; if (!string.IsNullOrWhiteSpace(author) && author.Equals("Advanced Micro Devices", StringComparison.OrdinalIgnoreCase)) { @@ -73,7 +78,7 @@ private static bool IsRadeonTask(Task scheduledTask) || name.Equals("StartCNBM", StringComparison.OrdinalIgnoreCase) || name.Equals("StartDVR", StringComparison.OrdinalIgnoreCase)) { - StaticViewModel.AddDebugMessage($"Found scheduled task {name}"); + _logger.Debug($"Found scheduled task {name}"); return true; } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/ScheduledTaskModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/ScheduledTaskModel.cs similarity index 57% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/ScheduledTaskModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/ScheduledTaskModel.cs index 70b2479..decb34a 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/ScheduledTaskModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/ScheduledTaskModel.cs @@ -1,30 +1,34 @@ using System; using System.ComponentModel; -using System.Globalization; -using Microsoft.Win32.TaskScheduler; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; +using RadeonSoftwareSlimmer.Core.Enums; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class ScheduledTaskModel : INotifyPropertyChanged { + private readonly IAppLogger _logger; + private readonly IScheduledTaskService _taskService; private bool _enabled; private bool _active; private TaskState _state; - public ScheduledTaskModel(Task scheduledTask) + public ScheduledTaskModel(IScheduledTask task, IAppLogger logger, IScheduledTaskService taskService) { - if (scheduledTask == null) - throw new ArgumentNullException(nameof(scheduledTask), "Scheduled Task is null"); - - Description = scheduledTask.Definition.RegistrationInfo.Description; - Enabled = scheduledTask.Enabled; - Name = scheduledTask.Name; - Active = scheduledTask.IsActive; - State = scheduledTask.State; - Command = scheduledTask.Definition.Actions[0].ToString(CultureInfo.CurrentCulture); - LastRun = scheduledTask.LastRunTime; + _logger = logger; + _taskService = taskService; + + if (task == null) + throw new ArgumentNullException(nameof(task), "Scheduled Task is null"); + + Description = task.Description; + Enabled = task.Enabled; + Name = task.Name; + Active = task.IsActive; + State = task.State; + Command = task.Command; + LastRun = task.LastRunTime; } @@ -67,12 +71,12 @@ private set public void Enable() { - using (Task task = TaskService.Instance.GetTask(Name)) + using (IScheduledTask task = _taskService.GetTask(Name)) { - if (!task.Definition.Settings.Enabled) + if (!task.Enabled) { - StaticViewModel.AddDebugMessage($"Enabling scheduled task {Name}"); - task.Definition.Settings.Enabled = true; + _logger.Debug($"Enabling scheduled task {Name}"); + task.Enabled = true; task.RegisterChanges(); @@ -85,15 +89,15 @@ public void Enable() public void Disable() { - using (Task task = TaskService.Instance.GetTask(Name)) + using (IScheduledTask task = _taskService.GetTask(Name)) { - if (task.Definition.Settings.Enabled) + if (task.Enabled) { - StaticViewModel.AddDebugMessage($"Stopping scheduled task {Name}"); + _logger.Debug($"Stopping scheduled task {Name}"); task.Stop(); - StaticViewModel.AddDebugMessage($"Disabling scheduled task {Name}"); - task.Definition.Settings.Enabled = false; + _logger.Debug($"Disabling scheduled task {Name}"); + task.Enabled = false; task.RegisterChanges(); diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs similarity index 91% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs index 3e130c0..6ebc770 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs @@ -1,18 +1,19 @@ using System.Collections.Generic; using System.ComponentModel; using RadeonSoftwareSlimmer.Core.Interfaces; -using RadeonSoftwareSlimmer.ViewModels; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class ServiceListModel : INotifyPropertyChanged { private readonly IRegistry _registry; + private readonly IAppLogger _logger; private IEnumerable _services; - public ServiceListModel(IRegistry registry) + public ServiceListModel(IRegistry registry, IAppLogger logger) { + _logger = logger; _registry = registry; } @@ -97,11 +98,11 @@ private IEnumerable GetAllRadeonServices() foreach (string service in serviceNames) { - ServiceModel serviceModel = new ServiceModel(service, _registry); + ServiceModel serviceModel = new ServiceModel(service, _registry, _logger); if (serviceModel.Exists()) { - StaticViewModel.AddDebugMessage($"Found service {service}"); + _logger.Debug($"Found service {service}"); yield return serviceModel; } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs similarity index 80% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs index 6b7b47a..231cb57 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/ServiceModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs @@ -1,16 +1,15 @@ using System; using System.ComponentModel; -using System.ServiceProcess; using RadeonSoftwareSlimmer.Core.Enums; using RadeonSoftwareSlimmer.Core.Interfaces; -using RadeonSoftwareSlimmer.Services; -using RadeonSoftwareSlimmer.ViewModels; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class ServiceModel : INotifyPropertyChanged { private readonly IRegistry _registry; + private readonly IAppLogger _logger; + private readonly IProcessRunner _processRunner; private readonly bool _exists; private bool _enabled; private ServiceStartMode _startMode; @@ -18,13 +17,17 @@ public class ServiceModel : INotifyPropertyChanged private ServiceControllerStatus _status; private readonly ServiceType _serviceType; + private readonly string _scExe; + private const string SERVICES_REG_KEY = @"SYSTEM\CurrentControlSet\Services\"; private const string SERVICE_START_VALUE_NAME = "Start"; private const string SERVICE_ORIGINAL_START_VALUE_NAME = "RadeonSoftwareSlimmerOriginalStart"; - public ServiceModel(string serviceName, IRegistry registry) + public ServiceModel(string serviceName, IRegistry registry, IAppLogger logger, IProcessRunner processRunner) { + _logger = logger; _registry = registry; + _processRunner = processRunner; using (ServiceController serviceController = new ServiceController(serviceName)) { @@ -46,6 +49,8 @@ public ServiceModel(string serviceName, IRegistry registry) _exists = false; } } + + _scExe = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "sc.exe"); } @@ -103,20 +108,20 @@ public void TryStart() { if (_startMode == ServiceStartMode.Disabled) { - StaticViewModel.AddLogMessage($"Cannot start {Name} because it is disabled"); + _logger.Info($"Cannot start {Name} because it is disabled"); return; } if (_serviceType.HasFlag(ServiceType.KernelDriver)) { - StaticViewModel.AddLogMessage($"Cannot start {Name} because it is a kernel driver"); + _logger.Info($"Cannot start {Name} because it is a kernel driver"); return; } try { - StaticViewModel.AddLogMessage("Restarting " + Name); - StaticViewModel.IsLoading = true; + _logger.Info("Restarting " + Name); + _logger.IsLoading = true; TryStop(); @@ -128,17 +133,17 @@ public void TryStart() serviceController.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30)); Status = serviceController.Status; - StaticViewModel.AddLogMessage("Restarted " + Name); + _logger.Info("Restarted " + Name); } } } catch (Exception ex) { - StaticViewModel.AddLogMessage(ex, "Failed to restart " + Name); + _logger.Info(ex, "Failed to restart " + Name); } finally { - StaticViewModel.IsLoading = false; + _logger.IsLoading = false; } } @@ -146,14 +151,14 @@ public void TryStop() { if (_serviceType.HasFlag(ServiceType.KernelDriver)) { - StaticViewModel.AddLogMessage($"Cannot stop {Name} because it is a kernel driver"); + _logger.Info($"Cannot stop {Name} because it is a kernel driver"); return; } try { - StaticViewModel.AddLogMessage("Stopping " + Name); - StaticViewModel.IsLoading = true; + _logger.Info("Stopping " + Name); + _logger.IsLoading = true; using (ServiceController serviceController = LoadFreshService()) { @@ -166,22 +171,22 @@ public void TryStop() } catch (InvalidOperationException ex) { - StaticViewModel.AddDebugMessage(ex); + _logger.Debug(ex); } Status = serviceController.Status; } } - StaticViewModel.AddLogMessage("Stopped " + Name); + _logger.Info("Stopped " + Name); } catch (Exception ex) { - StaticViewModel.AddLogMessage(ex, "Failed to stop " + Name); + _logger.Info(ex, "Failed to stop " + Name); } finally { - StaticViewModel.IsLoading = false; + _logger.IsLoading = false; } } @@ -191,11 +196,8 @@ public void Delete() using (ServiceController serviceController = LoadFreshService()) { - ProcessHandler processHandler = new ProcessHandler(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\sc.exe"); - processHandler.RunProcess($"delete \"{Name}\""); - + _processRunner.RunProcess(_scExe, $"delete \"{Name}\""); //Should delete the driver from the driver store and uninstall using pnputil - serviceController.Refresh(); } } @@ -207,8 +209,7 @@ public void Enable() if (StartMode == ServiceStartMode.Disabled && OriginalStartMode != ServiceStartMode.Disabled) { //It's this or WMI... - ProcessHandler processHandler = new ProcessHandler(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\sc.exe"); - processHandler.RunProcess($"config \"{Name}\" start= {GetStartModeCommandString(OriginalStartMode)}"); + _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(OriginalStartMode)}"); if (_serviceType == ServiceType.Win32OwnProcess) TryStart(); @@ -230,8 +231,7 @@ public void Disable() TryStop(); //It's this or WMI... - ProcessHandler processHandler = new ProcessHandler(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\sc.exe"); - processHandler.RunProcess($"config \"{Name}\" start= {GetStartModeCommandString(ServiceStartMode.Disabled)}"); + _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(ServiceStartMode.Disabled)}"); serviceController.Refresh(); StartMode = serviceController.StartType; @@ -252,14 +252,13 @@ private void SetStartMode(ServiceStartMode startMode) using (ServiceController serviceController = LoadFreshService()) { //It's this or WMI... - ProcessHandler processHandler = new ProcessHandler(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\sc.exe"); - processHandler.RunProcess($"config \"{Name}\" start= {GetStartModeCommandString(startMode)}"); + _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(startMode)}"); serviceController.Refresh(); StartMode = serviceController.StartType; Enabled = serviceController.StartType != ServiceStartMode.Disabled; - StaticViewModel.AddLogMessage($"Changed start mode for {Name} to {StartMode}"); + _logger.Info($"Changed start mode for {Name} to {StartMode}"); } } @@ -310,7 +309,7 @@ private void LoadOriginalStartMode() if (original != null) OriginalStartMode = (ServiceStartMode)original; else - StaticViewModel.AddDebugMessage("Unable to determin original start mode"); + _logger.Debug("Unable to determin original start mode"); } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/TempFileListModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/TempFileListModel.cs similarity index 93% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/TempFileListModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/TempFileListModel.cs index 91104d0..628bb57 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/TempFileListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/TempFileListModel.cs @@ -2,18 +2,20 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO.Abstractions; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class TempFileListModel : INotifyPropertyChanged { private readonly IFileSystem _fileSystem; + private readonly IAppLogger _logger; private IEnumerable _tempFiles; - public TempFileListModel(IFileSystem fileSystem) + public TempFileListModel(IFileSystem fileSystem, IAppLogger logger) { + _logger = logger; _fileSystem = fileSystem; } @@ -96,12 +98,12 @@ private IEnumerable GetAllRadeonTempFiles() { if (_fileSystem.Directory.Exists(tempFolder)) { - StaticViewModel.AddDebugMessage($"Found temp folder {tempFolder}"); - yield return new TempFileModel(tempFolder, _fileSystem); + _logger.Debug($"Found temp folder {tempFolder}"); + yield return new TempFileModel(tempFolder, _fileSystem, _logger); } else { - StaticViewModel.AddDebugMessage($"Folder {tempFolder} does not exist or cannot be accessed"); + _logger.Debug($"Folder {tempFolder} does not exist or cannot be accessed"); } } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/TempFileModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/TempFileModel.cs similarity index 85% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/TempFileModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/TempFileModel.cs index 1616677..ba65b29 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/TempFileModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/TempFileModel.cs @@ -2,21 +2,23 @@ using System.ComponentModel; using System.IO; using System.IO.Abstractions; -using RadeonSoftwareSlimmer.ViewModels; +using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class TempFileModel : INotifyPropertyChanged { private readonly IFileSystem _fileSystem; + private readonly IAppLogger _logger; //1024 instead of 1000, since this isn't a disk drive manufacturer... private const float DIV = 1024.0F; private bool _delete; - public TempFileModel(string folder, IFileSystem fileSystem) + public TempFileModel(string folder, IFileSystem fileSystem, IAppLogger logger) { + _logger = logger; _fileSystem = fileSystem; Clear = false; Folder = folder; @@ -45,7 +47,7 @@ public bool Clear public void ClearFolder() { - StaticViewModel.AddLogMessage($"Clearing folder {Folder}"); + _logger.Info($"Clearing folder {Folder}"); ClearFolder(Folder); } @@ -66,7 +68,7 @@ private void CalculateSize() } catch (Exception ex) { - StaticViewModel.AddDebugMessage(ex, $"Unable to determine file size of {fileInfo.FullName}"); + _logger.Debug(ex, $"Unable to determine file size of {fileInfo.FullName}"); } } @@ -101,7 +103,7 @@ private void ClearFolder(string folder) } catch (Exception ex) { - StaticViewModel.AddDebugMessage(ex, $"Unable to delete {fileInfo.FullName}"); + _logger.Debug(ex, $"Unable to delete {fileInfo.FullName}"); } } @@ -115,7 +117,7 @@ private void ClearFolder(string folder) } catch (Exception ex) { - StaticViewModel.AddDebugMessage(ex, $"Unable to delete {subDirectoryInfo.FullName}"); + _logger.Debug(ex, $"Unable to delete {subDirectoryInfo.FullName}"); } } } diff --git a/src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs similarity index 83% rename from src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs rename to src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs index 7387f42..03351b5 100644 --- a/src/RadeonSoftwareSlimmer/Models/PostInstall/WindowsAppStartupModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs @@ -3,7 +3,7 @@ using RadeonSoftwareSlimmer.Core.Enums; using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Models.PostInstall +namespace RadeonSoftwareSlimmer.Core.PostInstall { public class WindowsAppStartupModel : INotifyPropertyChanged { @@ -13,12 +13,12 @@ public class WindowsAppStartupModel : INotifyPropertyChanged #if NET48 private static readonly DateTime UNIX_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); #endif - private static readonly string RSX_LAUNCHER_REG_PATH = @"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\SystemAppData\AdvancedMicroDevicesInc-RSXCM_fhmx3h6dzfmvj\launcherrsxruntimeTask"; - private static readonly string RSX_LAUNCHER_REG_STATUS_NAME = "State"; - private static readonly string RSX_LAUNCHER_REG_LASTDISABLEDTIME_NAME = "LastDisabledTime"; + private const string RSX_LAUNCHER_REG_PATH = @"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\SystemAppData\AdvancedMicroDevicesInc-RSXCM_fhmx3h6dzfmvj\launcherrsxruntimeTask"; + private const string RSX_LAUNCHER_REG_STATUS_NAME = "State"; + private const string RSX_LAUNCHER_REG_LASTDISABLEDTIME_NAME = "LastDisabledTime"; private static readonly object STATE_ENABLED_VALUE = 2; private static readonly object STATE_DISABLED_VALUE = 1; - private static readonly string RSX_LAUNCHER_REG_STARTUPONCE_NAME = "UserEnabledStartupOnce"; + private const string RSX_LAUNCHER_REG_STARTUPONCE_NAME = "UserEnabledStartupOnce"; private static readonly object STATE_STARTUPONCE_YES = 1; private readonly IRegistry _registry; @@ -71,15 +71,15 @@ public void LoadOrRefresh() object state = launcherKey.GetValue(RSX_LAUNCHER_REG_STATUS_NAME); - if (state != null && state.Equals(STATE_ENABLED_VALUE)) + if (state?.Equals(STATE_ENABLED_VALUE) == true) Enabled = true; - if (state == null || state.Equals(STATE_DISABLED_VALUE)) + if (state?.Equals(STATE_DISABLED_VALUE) != false) { // Any other value besides enabled (2) is treated as disabled (1) // If the flag that the user has enabled statup once isn't set (0 or missing), then it will be re-enabled next logon/reboot object startupOnce = launcherKey.GetValue(RSX_LAUNCHER_REG_STARTUPONCE_NAME); - if (startupOnce != null && startupOnce.Equals(STATE_STARTUPONCE_YES)) + if (startupOnce?.Equals(STATE_STARTUPONCE_YES) == true) Enabled = false; else Enabled = true; diff --git a/src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs b/src/RadeonSoftwareSlimmer.Windows/ProcessHandler.cs similarity index 66% rename from src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs rename to src/RadeonSoftwareSlimmer.Windows/ProcessHandler.cs index f760eb4..d6f43e6 100644 --- a/src/RadeonSoftwareSlimmer.Core/Services/ProcessHandler.cs +++ b/src/RadeonSoftwareSlimmer.Windows/ProcessHandler.cs @@ -3,39 +3,37 @@ using System.Threading; using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Core.Services +namespace RadeonSoftwareSlimmer.Windows { public class ProcessHandler : IProcessHandler { private readonly IAppLogger _logger; - private readonly string _processName; - public ProcessHandler(string processName, IAppLogger logger) + public ProcessHandler(IAppLogger logger) { _logger = logger; - _processName = processName; } - public bool IsProcessRunning() + public bool IsProcessRunning(string processName) { - if (string.IsNullOrWhiteSpace(_processName)) + if (string.IsNullOrWhiteSpace(processName)) return false; - return Process.GetProcessesByName(_processName).Length > 0; + return Process.GetProcessesByName(processName).Length > 0; } - public void WaitForProcessToEnd(int maxWaitSeconds) + public void WaitForProcessToEnd(string processName, int maxWaitSeconds) { Stopwatch sw = new Stopwatch(); sw.Start(); - while (IsProcessRunning()) + while (IsProcessRunning(processName)) { if (sw.ElapsedMilliseconds >= maxWaitSeconds * 1000) { - foreach (Process process in Process.GetProcessesByName(_processName)) + foreach (Process process in Process.GetProcessesByName(processName)) { try { @@ -52,16 +50,16 @@ public void WaitForProcessToEnd(int maxWaitSeconds) } } - public void WaitForProcessToStart(int maxWaitSeconds) + public void WaitForProcessToStart(string processName, int maxWaitSeconds) { Stopwatch sw = new Stopwatch(); sw.Start(); - while (!IsProcessRunning()) + while (!IsProcessRunning(processName)) { if (sw.ElapsedMilliseconds >= maxWaitSeconds * 1000) { - _logger.Debug($"Process {_processName} did not start"); + _logger.Debug($"Process {processName} did not start"); return; } diff --git a/src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs b/src/RadeonSoftwareSlimmer.Windows/ProcessRunner.cs similarity index 97% rename from src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs rename to src/RadeonSoftwareSlimmer.Windows/ProcessRunner.cs index cf21d9d..ee3ab0b 100644 --- a/src/RadeonSoftwareSlimmer.Core/Services/ProcessRunner.cs +++ b/src/RadeonSoftwareSlimmer.Windows/ProcessRunner.cs @@ -2,7 +2,7 @@ using System.IO.Abstractions; using RadeonSoftwareSlimmer.Core.Interfaces; -namespace RadeonSoftwareSlimmer.Core.Services +namespace RadeonSoftwareSlimmer.Windows { public class ProcessRunner : IProcessRunner { From b115dfe732f497869219ddbcbe7a20b8267286ec Mon Sep 17 00:00:00 2001 From: Greg Seaton Date: Fri, 8 May 2026 01:10:40 -0400 Subject: [PATCH 4/4] Core builds --- .vscode/settings.json | 7 +- Directory.Packages.props | 8 +- build/build.sh | 14 -- build/publish.sh | 30 ---- build/test.sh | 33 ---- local-ci.sh | 18 +- src/README.md | 15 ++ .../Enums/ServiceControllerStatus.cs | 14 ++ .../Enums/ServiceStartMode.cs | 12 ++ .../Enums/ServiceType.cs | 15 ++ .../Interfaces/IServiceController.cs | 24 +++ .../PostInstall/ServiceListModel.cs | 8 +- .../PostInstall/ServiceModel.cs | 154 +++++++----------- .../PostInstall/WindowsAppStartupModel.cs | 2 +- .../RadeonSoftwareSlimmer.Core.Test.csproj | 13 +- .../TestTests.cs | 15 ++ .../RadeonSoftwareSlimmer.Test.runsettings | 0 17 files changed, 192 insertions(+), 190 deletions(-) delete mode 100644 build/build.sh delete mode 100644 build/publish.sh delete mode 100644 build/test.sh create mode 100644 src/README.md create mode 100644 src/RadeonSoftwareSlimmer.Core/Enums/ServiceControllerStatus.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Enums/ServiceStartMode.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Enums/ServiceType.cs create mode 100644 src/RadeonSoftwareSlimmer.Core/Interfaces/IServiceController.cs create mode 100644 test/RadeonSoftwareSlimmer.Core.Test/TestTests.cs rename test/{RadeonSoftwareSlimmer.Test => }/RadeonSoftwareSlimmer.Test.runsettings (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index fb38bbe..cd5935d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,9 @@ { "files.insertFinalNewline": true, - "files.trimFinalNewlines": true + "files.trimFinalNewlines": true, + "csharp-dev-tools.roslyn.roslynatorAnalyzersEnabled": false, + "csharp-dev-tools.roslyn.roslynatorCodeFixesEnabled": false, + "csharp-dev-tools.roslyn.roslynatorEnabled": false, + "csharp-dev-tools.roslyn.roslynatorFormattingAnalyzersEnabled": false, + "csharp-dev-tools.roslyn.roslynatorRefactoringsEnabled": false } diff --git a/Directory.Packages.props b/Directory.Packages.props index ca5d87f..a3aa20d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,13 +6,13 @@ - + - - + + - + diff --git a/build/build.sh b/build/build.sh deleted file mode 100644 index 5a37611..0000000 --- a/build/build.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -eu - - -version=$BUILD_VERSION -echo "Version: ${version}" - -echo '***** Building solution...' -dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net10.0 -#dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net9.0-windows -#dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net8.0-windows -#dotnet build --no-incremental --force --configuration Release -p:Version=$version --framework net48 -echo '***** Done Building solution...' diff --git a/build/publish.sh b/build/publish.sh deleted file mode 100644 index a61250b..0000000 --- a/build/publish.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -eu - - -version=BUILD_VERSION -echo"Version: ${version}" - - -echo '***** Publishing Application...' -dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net10.0 -#dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net9.0-windows -#dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net8.0-windows -#dotnet publish ./src/RadeonSoftwareSlimmer/RadeonSoftwareSlimmer.csproj --force --configuration Release -p:Version=$version --framework net48 -echo '***** Done Publishing Application...' - - -echo '***** Archiving Application...' -publishSrcDir='./artifacts/publish/RadeonSoftwareSlimmer' -publishDestDir='./artifacts/publish' - -zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net90.zip" "${publishSrcDir}/release_net10.0-x64/*" -#zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net90.zip" "${publishSrcDir}/release_net9.0-windows_win-x64/*" -#zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net80.zip" "${publishSrcDir}/release_net8.0-windows_win-x64/*" -#zip -r "${publishDestDir}/RadeonSoftwareSlimmer_${version}_net48.zip" "${publishSrcDir}/release_net48_win-x64/*" -echo '***** Done Archiving Application...' - - -echo '***** Archive Hashes (SHA256):' -sha256sum "${publishDestDir}\RadeonSoftwareSlimmer_*_net*.zip" diff --git a/build/test.sh b/build/test.sh deleted file mode 100644 index cd8c6bd..0000000 --- a/build/test.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -eu - - -artifactPath='./artifacts' -resultsPath='./artifacts/tests' - - -echo '***** Installing Report Generator...' -dotnet tool install dotnet-reportgenerator-globaltool --tool-path $artifactPath - - -echo '***** Testing solution...' -# https://github.com/dotnet/sdk/issues/44991 - does not support artifact output -project='./test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.csproj' - -dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net10.0 -#dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net9.0-windows -#dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net8.0-windows -#dotnet test $project --no-build --configuration Release --results-directory $resultsPath --framework net48 -echo '***** Done Testing solution...' - - -echo '***** Running Report Generator...' -#$reportGenArgs = @( -# "-reports:${resultsPath}\*\coverage.cobertura*.xml", -# "-targetdir:${artifactPath}\CoverageReports", -# '-reporttypes:Badges;Cobertura;Html;HtmlSummary;TextSummary', -# '--settings:createSubdirectoryForAllReportTypes=true' -#) -#Start-Process -FilePath "${artifactPath}\reportgenerator.exe" -ArgumentList $reportGenArgs -NoNewWindow -Wait -#Get-Content -Path "${artifactPath}\CoverageReports\TextSummary\Summary.txt" diff --git a/local-ci.sh b/local-ci.sh index bd2e5be..8a3af7b 100644 --- a/local-ci.sh +++ b/local-ci.sh @@ -3,21 +3,29 @@ set -eu -export BUILD_VERSION='1.2.3-localci' +export version='1.2.3-localci' echo '***** Recreating artifacts directory...' artifactPath='./artifacts' +resultsPath='./artifacts/tests' + echo $artifactPath if [[ -d "${artifactPath}" ]]; then rm --recursive --force "${artifactPath:?}/*" fi +project='./src/RadeonSoftwareSlimmer.Core/RadeonSoftwareSlimmer.Core.csproj' +testProject='./test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj' -bash ./build/build.sh - -bash ./build/test.sh +echo '***** Building Core Project...' +dotnet build $project --no-incremental --force --configuration Release -p:Version=$version -bash ./build/publish.sh +echo '***** Building Core Test Project...' +dotnet build $testProject --no-incremental --force --configuration Release -p:Version=$version --framework net10.0 +echo '***** Done Building' +echo '***** Testing...' +# https://github.com/dotnet/sdk/issues/44991 - does not support artifact output +dotnet test $testProject --no-build --configuration Release --results-directory $resultsPath --framework net10.0 echo '***** Done!' diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..cb76676 --- /dev/null +++ b/src/README.md @@ -0,0 +1,15 @@ +# Source + +The source is split into 3 projects. This is mainly to improve testability on non-Windows platforms, despite the application only for running on Windows. + +## Radeon.Software.Slimmer + +The main WPF project that ties everything together and produces the executable users run. It references the Core and Windwos projects. All the UI code is in here. + +## Radeon.Software.Slimmer.Core + +The Core project contains the bulk of the back-end logic. It has abstractions around all the Windows only code to allow local development on other platforms. Tests can verify business logic without needing Windows. + +## RadeonSoftwareSlimmer.Windows + +This project implements all the abstractions in the Core with the Windows specific logic. Windows Registy, Scheduled Tasks, NT Services, etc. The tests against this verify the integration points with the local Windows OS. diff --git a/src/RadeonSoftwareSlimmer.Core/Enums/ServiceControllerStatus.cs b/src/RadeonSoftwareSlimmer.Core/Enums/ServiceControllerStatus.cs new file mode 100644 index 0000000..8fef4c9 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Enums/ServiceControllerStatus.cs @@ -0,0 +1,14 @@ +namespace RadeonSoftwareSlimmer.Core.Enums +{ + // https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicecontrollerstatus + public enum ServiceControllerStatus : int + { + Stopped = 1, + StartPending = 2, + StopPending = 3, + Running = 4, + ContinuePending = 5, + PausePending = 6, + Paused = 7 + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Enums/ServiceStartMode.cs b/src/RadeonSoftwareSlimmer.Core/Enums/ServiceStartMode.cs new file mode 100644 index 0000000..bf22d88 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Enums/ServiceStartMode.cs @@ -0,0 +1,12 @@ +namespace RadeonSoftwareSlimmer.Core.Enums +{ + // https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicestartmode + public enum ServiceStartMode : int + { + Boot = 0, + System = 1, + Automatic = 2, + Manual = 3, + Disabled = 4 + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Enums/ServiceType.cs b/src/RadeonSoftwareSlimmer.Core/Enums/ServiceType.cs new file mode 100644 index 0000000..8a2f6d2 --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Enums/ServiceType.cs @@ -0,0 +1,15 @@ +namespace RadeonSoftwareSlimmer.Core.Enums +{ + // https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicetype + [System.Flags] + public enum ServiceType : int + { + KernelDriver = 1, + FileSystemDriver = 2, + Adapter = 4, + RecognizerDriver = 8, + Win32OwnProcess = 16, + Win32ShareProcess = 32, + InteractiveProcess = 256 + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/Interfaces/IServiceController.cs b/src/RadeonSoftwareSlimmer.Core/Interfaces/IServiceController.cs new file mode 100644 index 0000000..cb065da --- /dev/null +++ b/src/RadeonSoftwareSlimmer.Core/Interfaces/IServiceController.cs @@ -0,0 +1,24 @@ +using RadeonSoftwareSlimmer.Core.Enums; +using System; + + +namespace RadeonSoftwareSlimmer.Core.Interfaces +{ + // https://dahall.github.io/TaskScheduler/html/T_Microsoft_Win32_TaskScheduler_TaskService.htm + public interface IServiceController + { + string ServiceName { get; } + bool Exists { get; } // InvalidOperationException = does not exist + string DisplayName { get; } + ServiceStartMode StartType { get; } + ServiceType ServiceType { get; } + ServiceControllerStatus Status { get; } + + void Load(string serviceName); + + void Start(); + void Stop(); + void Refresh(); + void WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeout); + } +} diff --git a/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs index 6ebc770..e1f8409 100644 --- a/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceListModel.cs @@ -8,13 +8,17 @@ public class ServiceListModel : INotifyPropertyChanged { private readonly IRegistry _registry; private readonly IAppLogger _logger; + private readonly IProcessRunner _processRunner; + private readonly IServiceController _serviceController; private IEnumerable _services; - public ServiceListModel(IRegistry registry, IAppLogger logger) + public ServiceListModel(IRegistry registry, IAppLogger logger, IProcessRunner processRunner, IServiceController serviceController) { _logger = logger; _registry = registry; + _processRunner = processRunner; + _serviceController = serviceController; } @@ -98,7 +102,7 @@ private IEnumerable GetAllRadeonServices() foreach (string service in serviceNames) { - ServiceModel serviceModel = new ServiceModel(service, _registry, _logger); + ServiceModel serviceModel = new ServiceModel(service, _registry, _logger, _processRunner, _serviceController); if (serviceModel.Exists()) { diff --git a/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs index 231cb57..98bf550 100644 --- a/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/ServiceModel.cs @@ -10,6 +10,7 @@ public class ServiceModel : INotifyPropertyChanged private readonly IRegistry _registry; private readonly IAppLogger _logger; private readonly IProcessRunner _processRunner; + private readonly IServiceController _serviceController; private readonly bool _exists; private bool _enabled; private ServiceStartMode _startMode; @@ -23,34 +24,29 @@ public class ServiceModel : INotifyPropertyChanged private const string SERVICE_START_VALUE_NAME = "Start"; private const string SERVICE_ORIGINAL_START_VALUE_NAME = "RadeonSoftwareSlimmerOriginalStart"; - public ServiceModel(string serviceName, IRegistry registry, IAppLogger logger, IProcessRunner processRunner) + public ServiceModel(string serviceName, IRegistry registry, IAppLogger logger, IProcessRunner processRunner, IServiceController serviceController) { _logger = logger; _registry = registry; _processRunner = processRunner; + _serviceController = serviceController; - using (ServiceController serviceController = new ServiceController(serviceName)) + _serviceController.Load(serviceName); + _exists = _serviceController.Exists; + + if (_exists) { - try - { - Name = serviceController.ServiceName; - DisplayName = serviceController.DisplayName; - _exists = true; - Enabled = serviceController.StartType != ServiceStartMode.Disabled; - StartMode = serviceController.StartType; - _serviceType = serviceController.ServiceType; - Status = serviceController.Status; - - LoadOriginalStartMode(); - } - catch (InvalidOperationException) - { - // Can't find a better way to handle servics that don't exist :( - _exists = false; - } - } + Name = serviceController.ServiceName; + DisplayName = serviceController.DisplayName; + Enabled = serviceController.StartType != ServiceStartMode.Disabled; + StartMode = serviceController.StartType; + _serviceType = serviceController.ServiceType; + Status = serviceController.Status; + + LoadOriginalStartMode(); - _scExe = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "sc.exe"); + _scExe = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "sc.exe"); + } } @@ -125,16 +121,14 @@ public void TryStart() TryStop(); - using (ServiceController serviceController = LoadFreshService()) + _serviceController.Refresh(); + if (_serviceController.StartType != ServiceStartMode.Disabled && _serviceController.ServiceType.HasFlag(ServiceType.Win32OwnProcess)) { - if (serviceController.StartType != ServiceStartMode.Disabled && serviceController.ServiceType.HasFlag(ServiceType.Win32OwnProcess)) - { - serviceController.Start(); - serviceController.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30)); + _serviceController.Start(); + _serviceController.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30)); - Status = serviceController.Status; - _logger.Info("Restarted " + Name); - } + Status = _serviceController.Status; + _logger.Info("Restarted " + Name); } } catch (Exception ex) @@ -160,22 +154,20 @@ public void TryStop() _logger.Info("Stopping " + Name); _logger.IsLoading = true; - using (ServiceController serviceController = LoadFreshService()) + _serviceController.Refresh(); + if (_serviceController.Status == ServiceControllerStatus.Running && _serviceController.ServiceType.HasFlag(ServiceType.Win32OwnProcess)) { - if (serviceController.Status == ServiceControllerStatus.Running && serviceController.ServiceType.HasFlag(ServiceType.Win32OwnProcess)) + try + { + _serviceController.Stop(); + _serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30)); + } + catch (InvalidOperationException ex) { - try - { - serviceController.Stop(); - serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30)); - } - catch (InvalidOperationException ex) - { - _logger.Debug(ex); - } - - Status = serviceController.Status; + _logger.Debug(ex); } + + Status = _serviceController.Status; } _logger.Info("Stopped " + Name); @@ -190,53 +182,47 @@ public void TryStop() } } + // Consider moving all this below to IServiceController instead of here + public void Delete() { TryStop(); - using (ServiceController serviceController = LoadFreshService()) - { - _processRunner.RunProcess(_scExe, $"delete \"{Name}\""); - //Should delete the driver from the driver store and uninstall using pnputil - serviceController.Refresh(); - } + _processRunner.RunProcess(_scExe, $"delete \"{Name}\""); + _serviceController.Refresh(); } public void Enable() { - using (ServiceController serviceController = LoadFreshService()) + _serviceController.Refresh(); + if (StartMode == ServiceStartMode.Disabled && OriginalStartMode != ServiceStartMode.Disabled) { - if (StartMode == ServiceStartMode.Disabled && OriginalStartMode != ServiceStartMode.Disabled) - { - //It's this or WMI... - _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(OriginalStartMode)}"); + //It's this or WMI... + _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(OriginalStartMode)}"); - if (_serviceType == ServiceType.Win32OwnProcess) - TryStart(); + if (_serviceType == ServiceType.Win32OwnProcess) + TryStart(); - serviceController.Refresh(); - StartMode = serviceController.StartType; - Enabled = serviceController.StartType != ServiceStartMode.Disabled; - } + _serviceController.Refresh(); + StartMode = _serviceController.StartType; + Enabled = _serviceController.StartType != ServiceStartMode.Disabled; } } public void Disable() { - using (ServiceController serviceController = LoadFreshService()) + _serviceController.Refresh(); + if (StartMode != ServiceStartMode.Disabled) { - if (StartMode != ServiceStartMode.Disabled) - { - if (_serviceType.HasFlag(ServiceType.Win32OwnProcess)) - TryStop(); + if (_serviceType.HasFlag(ServiceType.Win32OwnProcess)) + TryStop(); - //It's this or WMI... - _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(ServiceStartMode.Disabled)}"); + //It's this or WMI... + _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(ServiceStartMode.Disabled)}"); - serviceController.Refresh(); - StartMode = serviceController.StartType; - Enabled = serviceController.StartType != ServiceStartMode.Disabled; - } + _serviceController.Refresh(); + StartMode = _serviceController.StartType; + Enabled = _serviceController.StartType != ServiceStartMode.Disabled; } } @@ -249,30 +235,14 @@ public void SetStartMode(string startMode) private void SetStartMode(ServiceStartMode startMode) { - using (ServiceController serviceController = LoadFreshService()) - { - //It's this or WMI... - _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(startMode)}"); + //It's this or WMI... + _processRunner.RunProcess(_scExe, $"config \"{Name}\" start= {GetStartModeCommandString(startMode)}"); - serviceController.Refresh(); - StartMode = serviceController.StartType; - Enabled = serviceController.StartType != ServiceStartMode.Disabled; - - _logger.Info($"Changed start mode for {Name} to {StartMode}"); - } - } - - private ServiceController LoadFreshService() - { - if (_exists) - { - ServiceController serviceController = new ServiceController(Name); - serviceController.Refresh(); - - return serviceController; - } + _serviceController.Refresh(); + StartMode = _serviceController.StartType; + Enabled = _serviceController.StartType != ServiceStartMode.Disabled; - return new ServiceController(); + _logger.Info($"Changed start mode for {Name} to {StartMode}"); } private static string GetStartModeCommandString(ServiceStartMode serviceStartMode) diff --git a/src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs b/src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs index 03351b5..9c7394a 100644 --- a/src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs +++ b/src/RadeonSoftwareSlimmer.Core/PostInstall/WindowsAppStartupModel.cs @@ -10,7 +10,7 @@ public class WindowsAppStartupModel : INotifyPropertyChanged #if NET6_0_OR_GREATER private static readonly DateTime UNIX_EPOCH = DateTime.UnixEpoch; #endif -#if NET48 +#if ( NET48 || NETSTANDARD2_0 ) private static readonly DateTime UNIX_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); #endif private const string RSX_LAUNCHER_REG_PATH = @"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\SystemAppData\AdvancedMicroDevicesInc-RSXCM_fhmx3h6dzfmvj\launcherrsxruntimeTask"; diff --git a/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj b/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj index fd3c690..81c92ea 100644 --- a/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj +++ b/test/RadeonSoftwareSlimmer.Core.Test/RadeonSoftwareSlimmer.Core.Test.csproj @@ -1,6 +1,6 @@ - net10.0 + net10.0;net9.0;net8.0;net48 @@ -29,13 +29,10 @@ - - - PreserveNewest - - + + diff --git a/test/RadeonSoftwareSlimmer.Core.Test/TestTests.cs b/test/RadeonSoftwareSlimmer.Core.Test/TestTests.cs new file mode 100644 index 0000000..3615044 --- /dev/null +++ b/test/RadeonSoftwareSlimmer.Core.Test/TestTests.cs @@ -0,0 +1,15 @@ +using NUnit.Framework; + +namespace RadeonSoftwareSlimmer.Core.Test +{ + [TestFixture] + public class TestTests + { + [Test] + public void DummyTest() + { + bool test = true; + Assert.That(test, Is.True); + } + } +} diff --git a/test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.runsettings b/test/RadeonSoftwareSlimmer.Test.runsettings similarity index 100% rename from test/RadeonSoftwareSlimmer.Test/RadeonSoftwareSlimmer.Test.runsettings rename to test/RadeonSoftwareSlimmer.Test.runsettings