diff --git a/src/c#/GeneralUpdate.Client/Program.cs b/src/c#/GeneralUpdate.Client/Program.cs index 82782454..bcd1ce6b 100644 --- a/src/c#/GeneralUpdate.Client/Program.cs +++ b/src/c#/GeneralUpdate.Client/Program.cs @@ -4,7 +4,7 @@ internal class Program { static void Main(string[] args) { - Console.WriteLine("Hello, World!"); + Console.Read(); } } } diff --git a/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs index e09222ba..7c897954 100644 --- a/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs @@ -3,7 +3,6 @@ namespace GeneralUpdate.Core.Driver { - /// /// When the /export-driver command backs up a driver, it backs up the driver package along with all its dependencies, such as associated library files and other related files. /// @@ -11,22 +10,37 @@ public class BackupDriverCommand : IDriverCommand { private DriverInformation _information; - public BackupDriverCommand(DriverInformation information) - { - _information = information; - } - + public BackupDriverCommand(DriverInformation information)=> _information = information; + public void Execute() { /* * Back up the specified list of drives. */ - foreach (var driverName in _information.DriverNames) + foreach (var driver in _information.Drivers) { - var command = new StringBuilder("/c dism /online /export-driver /destination:\"") - .Append(Path.Combine(_information.OutPutDirectory, driverName)) - .Append("\"") + //Export the backup according to the driver name. + var outPutDirectory = Path.Combine(_information.OutPutDirectory, Path.GetFileNameWithoutExtension(driver)); + + if (Directory.Exists(outPutDirectory)) + Directory.Delete(outPutDirectory, true); + + Directory.CreateDirectory(outPutDirectory); + + /* + * If no test driver files are available, you can run the following command to export all installed driver files. + * (1) dism /online /export-driver /destination:"D:\packet\cache\" + * (2) pnputil /export-driver * D:\packet\cache + * + * The following code example exports the specified driver to the specified directory. + * pnputil /export-driver oem14.inf D:\packet\cache + */ + var command = new StringBuilder("/c pnputil /export-driver ") + .Append(driver) + .Append(' ') + .Append(outPutDirectory) .ToString(); + CommandExecutor.ExecuteCommand(command); } } diff --git a/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs b/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs index 208f1845..20055e5c 100644 --- a/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs +++ b/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs @@ -11,26 +11,24 @@ public class CommandExecutor public static void ExecuteCommand(string command) { /* + * *Problems may occur, including: Permission issues: PnPUtil requires administrator rights to run. If you try to run it without the proper permissions, the backup or restore may fail. Driver compatibility: Although the backed up drivers work properly at backup time, if the operating system is upgraded, the backed up drivers may no longer be compatible with the new operating system version. Hardware problems: If the hardware device fails or the hardware configuration changes, the backup driver may not work properly. -To minimize these risks, the following measures are recommended: + To minimize these risks, the following measures are recommended: Before doing anything, create a system restore point so that it can be restored to its previous state if something goes wrong. Update the driver regularly to ensure that the driver is compatible with the current operating system version. If possible, use pre-tested drivers that are proven to work. * */ - var processStartInfo = new ProcessStartInfo { WindowStyle = ProcessWindowStyle.Hidden, FileName = "cmd.exe", Arguments = command, - UseShellExecute = false, - RedirectStandardOutput = true, - CreateNoWindow = true, + UseShellExecute = true, Verb = "runas" }; @@ -40,7 +38,7 @@ Update the driver regularly to ensure that the driver is compatible with the cur process.WaitForExit(); if (process.ExitCode != 0) - throw new Exception("Operation failed: " + process.StandardOutput.ReadToEnd()); + throw new Exception($"Operation failed code: {process.ExitCode}"); } } } diff --git a/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs new file mode 100644 index 00000000..6fb4e1d5 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs @@ -0,0 +1,23 @@ +using System.Text; + +namespace GeneralUpdate.Core.Driver +{ + public class DeleteDriverCommand : IDriverCommand + { + private DriverInformation _information; + + public DeleteDriverCommand(DriverInformation information) => _information = information; + + public void Execute() + { + //Before installing the driver, delete the driver that has been installed on the local system. Otherwise, an exception may occur. + foreach (var driver in _information.Drivers) + { + var command = new StringBuilder("/c pnputil /delete-driver ") + .Append(driver) + .ToString(); + CommandExecutor.ExecuteCommand(command); + } + } + } +} diff --git a/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs b/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs index 95df5bf0..be975aaa 100644 --- a/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs +++ b/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs @@ -22,7 +22,7 @@ public class DriverInformation /// /// A collection of driver files to be backed up. /// - public List DriverNames { get; private set; } + public List Drivers { get; private set; } private DriverInformation(){} @@ -49,7 +49,7 @@ public Builder SetOutPutDirectory(string outPutDirectory) /// public Builder SetDriverNames(List driverNames) { - _information.DriverNames = driverNames; + _information.Drivers = driverNames; return this; } @@ -57,7 +57,7 @@ public DriverInformation Build() { if (string.IsNullOrWhiteSpace(_information.InstallDirectory) || string.IsNullOrWhiteSpace(_information.OutPutDirectory) || - !_information.DriverNames.Any()) + !_information.Drivers.Any()) { throw new InvalidOperationException("Cannot create DriverInformation, not all fields are set."); } diff --git a/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs b/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs index 8e927c82..9d02c28a 100644 --- a/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs +++ b/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs @@ -19,11 +19,14 @@ public void AddCommand(IDriverCommand command) /// public void ProcessCommands() { + /* + * This section describes the PnPUtil command. + * https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil-command-syntax + */ foreach (var command in _commands) { command.Execute(); } - _commands.Clear(); } } diff --git a/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs index 97ffe13f..9e7a61f0 100644 --- a/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Text; namespace GeneralUpdate.Core.Driver @@ -7,24 +8,32 @@ public class InstallDriverCommand : IDriverCommand { private DriverInformation _information; - public InstallDriverCommand(DriverInformation information) - { - _information = information; - } + public InstallDriverCommand(DriverInformation information)=> _information = information; public void Execute() { try { - //Install all drivers in the specified directory, and if the installation fails, restore all the drivers in the backup directory. - var command = new StringBuilder("/c pnputil /add-driver \"") - .Append(_information.InstallDirectory) - .Append("\"") - .ToString(); - CommandExecutor.ExecuteCommand(command); + foreach (var driver in _information.Drivers) + { + /* + * 1.It is best to ensure that the installed file is OEM INF, otherwise PnPUtil may indicate that non-OEM INF cannot perform the current operation. + * + * 2.Before installation, you need to delete the previously installed driver, otherwise PnPUtil will prompt 259 to exit the code. + * (On Windows, an ExitCode value of 259 (STILL_ACTIVE) means that the process is still running) + * If you do not remove the previous installation 259 prompt will give you a misleading impression of what is running. + */ + var path = Path.Combine(_information.InstallDirectory, Path.GetFileNameWithoutExtension(driver), driver); + var command = new StringBuilder("/c pnputil /add-driver ") + .Append(path) + .Append(" /install") + .ToString(); + CommandExecutor.ExecuteCommand(command); + } } catch (Exception ex) { + //restore all the drivers in the backup directory. new RestoreDriverCommand(_information).Execute(); throw new Exception($"Failed to execute install command for {_information.InstallDirectory}", ex); } diff --git a/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs index e24dbc59..b2c5d839 100644 --- a/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs @@ -1,4 +1,6 @@ -using System.Text; +using System.IO; +using System; +using System.Text; namespace GeneralUpdate.Core.Driver { @@ -6,19 +8,26 @@ public class RestoreDriverCommand : IDriverCommand { private DriverInformation _information; - public RestoreDriverCommand(DriverInformation information) - { - _information = information; - } + public RestoreDriverCommand(DriverInformation information)=> _information = information; public void Execute() { - //Restore all drives in the backup directory. - var command = new StringBuilder("/c pnputil /add-driver \"") - .Append(_information.OutPutDirectory) - .Append("\"") - .ToString(); - CommandExecutor.ExecuteCommand(command); + try + { + foreach (var driver in _information.Drivers) + { + //Install all drivers in the specified directory, and if the installation fails, restore all the drivers in the backup directory. + var command = new StringBuilder("/c pnputil /add-driver ") + .Append(Path.Combine(_information.OutPutDirectory, Path.GetFileNameWithoutExtension(driver), driver)) + .Append(" /install") + .ToString(); + CommandExecutor.ExecuteCommand(command); + } + } + catch (Exception ex) + { + throw new Exception($"Failed to execute restore command for {_information.OutPutDirectory}", ex); + } } } } \ No newline at end of file diff --git a/src/c#/TestCore/TestCore.csproj b/src/c#/TestCore/TestCore.csproj index 51e6422b..28ba577f 100644 --- a/src/c#/TestCore/TestCore.csproj +++ b/src/c#/TestCore/TestCore.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/src/c#/TestCore/UnitTest1.cs b/src/c#/TestCore/UnitTest1.cs index 671c5cb8..d6663d9b 100644 --- a/src/c#/TestCore/UnitTest1.cs +++ b/src/c#/TestCore/UnitTest1.cs @@ -1,16 +1,29 @@ +using GeneralUpdate.Core.Driver; + namespace TestCore { public class Tests { - [SetUp] - public void Setup() - { - } - [Test] public void Test1() { - Assert.Pass(); + string installDir = "D:\\packet\\patch"; + string outPutDir = "D:\\packet\\cache"; + string name = "netrasa.inf"; + + var information = new DriverInformation.Builder() + .SetInstallDirectory(installDir) + .SetOutPutDirectory(outPutDir) + .SetDriverNames(new List { name }) + .Build(); + + Assert.IsNotNull(information); + + var processor = new DriverProcessor(); + processor.AddCommand(new BackupDriverCommand(information)); + processor.AddCommand(new DeleteDriverCommand(information)); + processor.AddCommand(new InstallDriverCommand(information)); + processor.ProcessCommands(); } } } \ No newline at end of file