From a338f536a32042d1c6a2a650cb5c983a6aff2105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gonz=C3=A1lez=20Mart=C3=ADn?= <158048821+felgmar@users.noreply.github.com> Date: Thu, 8 May 2025 17:03:43 +0100 Subject: [PATCH 1/6] WindowsInstallerLib: implement ThreadManager --- WindowsInstallerLib/src/ThreadManager.cs | 119 +++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 WindowsInstallerLib/src/ThreadManager.cs diff --git a/WindowsInstallerLib/src/ThreadManager.cs b/WindowsInstallerLib/src/ThreadManager.cs new file mode 100644 index 0000000..8e9c95e --- /dev/null +++ b/WindowsInstallerLib/src/ThreadManager.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Threading; + +namespace WindowsInstallerLib +{ + /// + /// This class handles the priority, the state, etcetera of threads. + /// + internal sealed class ThreadManager + { + /// + /// Gets the current priority of the thread. + /// + /// + /// + /// BelowNormal, Normal, AboveNormal or Highest + /// + private static ThreadPriority GetThreadPriority(Thread thread) { return thread.Priority; } + private static ThreadPriority SetThreadPriority(Thread thread, ThreadPriority threadPriority) { return thread.Priority = threadPriority; } + private static ThreadState GetThreadState(Thread thread) { return thread.ThreadState; } + private static ApartmentState GetThreadApartmentState(Thread thread) { return thread.GetApartmentState(); } + private static bool TrySetThreadApartmentState(Thread thread, ApartmentState apartmentState) + { + try + { + return thread.TrySetApartmentState(apartmentState); + } + catch (PlatformNotSupportedException) + { + throw; + } + catch (ArgumentException) + { + throw; + } + catch (ThreadStateException) + { + throw; + } + } + private static Thread? GetCurrentThread() { return Thread.CurrentThread; } + internal static bool IsBackground(Thread thread) { return thread.IsBackground; } + internal static bool IsThreadAlive(Thread thread) { return thread.IsAlive; } + + internal static Thread CreateThread(Action action) + { + Thread thread = new(() => + { + action.Invoke(); + } + ); + + if (GetThreadState(thread) == ThreadState.Running) + { + //throw new InvalidOperationException($"Cannot modify the state of a thread when it is already running."); + thread.Join(); + } + + try + { + thread.IsBackground = true; + } + catch (ThreadStateException ex) + { + if (ex.InnerException != null) + { + throw ex.InnerException; + } + } + catch + { + throw; + } + + try + { + if (GetThreadPriority(thread) == ThreadPriority.Normal) + { + SetThreadPriority(thread, ThreadPriority.AboveNormal); + } + } + catch + { + throw; + } + + try + { + TrySetThreadApartmentState(thread, ApartmentState.MTA); + } + catch + { + throw; + } + + try + { + if (GetCurrentThread != null && + GetThreadState(thread) == ThreadState.Unstarted) + { + thread.Start(); + } + } + catch (Exception ex) + { + switch (ex.InnerException != null) + { + case true: + throw ex.InnerException; + case false: + throw; + } + } + return thread; + } + } +} From 6e257e1b0773ba2940ab42dbd53e4bcab87ac074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gonz=C3=A1lez=20Mart=C3=ADn?= <158048821+felgmar@users.noreply.github.com> Date: Thu, 8 May 2025 17:04:59 +0100 Subject: [PATCH 2/6] WindowsInstallerLib: add threaded wrappers for existing functions Add wrappers to the originals functions and call them by wrapping them around ThreadManager --- WindowsInstallerLib/src/ProcessManager.cs | 36 ++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/WindowsInstallerLib/src/ProcessManager.cs b/WindowsInstallerLib/src/ProcessManager.cs index 9f93231..9a54a11 100644 --- a/WindowsInstallerLib/src/ProcessManager.cs +++ b/WindowsInstallerLib/src/ProcessManager.cs @@ -22,7 +22,6 @@ internal static int StartCmdProcess(string fileName, string args) process.Start(); process.WaitForExit(); ExitCode = process.ExitCode; - } catch (InvalidOperationException) { @@ -40,6 +39,14 @@ internal static int StartCmdProcess(string fileName, string args) return ExitCode; } + internal static int StartCmdProcessThreaded(string fileName, string args) + { + ThreadManager.CreateThread( + () => StartCmdProcess(fileName, args) + ); + return ExitCode; + } + internal static int StartDiskPartProcess(int DiskNumber, string EfiDrive, string DestinationDrive) { Process process = new(); @@ -108,6 +115,15 @@ internal static int StartDiskPartProcess(int DiskNumber, string EfiDrive, string return ExitCode; } + internal static int StartDiskPartProcessThreaded(int DiskNumber, string EfiDrive, string DestinationDrive) + { + ThreadManager.CreateThread( + () => StartDiskPartProcess(DiskNumber, EfiDrive, DestinationDrive) + ); + + return ExitCode; + } + internal static int StartDismProcess(string args) { Process process = new(); @@ -141,6 +157,15 @@ internal static int StartDismProcess(string args) return ExitCode; } + internal static int StartDismProcessThreaded(string args) + { + ThreadManager.CreateThread( + () => StartDismProcess(args) + ); + + return ExitCode; + } + internal static int StartProcess(string filename, string args) { Process process = new(); @@ -177,5 +202,14 @@ internal static int StartProcess(string filename, string args) return ExitCode; } + + internal static int StartProcessThreaded(string filename, string args) + { + ThreadManager.CreateThread( + () => StartProcess(filename, args) + ); + + return ExitCode; + } } } From 01caad30f6765b84b259950bf6d2a3e95b508d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gonz=C3=A1lez=20Mart=C3=ADn?= <158048821+felgmar@users.noreply.github.com> Date: Tue, 20 May 2025 14:09:27 +0100 Subject: [PATCH 3/6] WindowsInstallerLib: remove unused usings --- WindowsInstallerLib/src/ThreadManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/WindowsInstallerLib/src/ThreadManager.cs b/WindowsInstallerLib/src/ThreadManager.cs index 8e9c95e..7302964 100644 --- a/WindowsInstallerLib/src/ThreadManager.cs +++ b/WindowsInstallerLib/src/ThreadManager.cs @@ -1,6 +1,4 @@ using System; -using System.Collections; -using System.Collections.Concurrent; using System.Threading; namespace WindowsInstallerLib From 76e8b87b7c16e292c759d659766429093c86b843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gonz=C3=A1lez=20Mart=C3=ADn?= <158048821+felgmar@users.noreply.github.com> Date: Tue, 20 May 2025 14:09:40 +0100 Subject: [PATCH 4/6] WindowsInstaller: add new threaded diskpart function --- WindowsInstallerLib/src/ProcessManager.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/WindowsInstallerLib/src/ProcessManager.cs b/WindowsInstallerLib/src/ProcessManager.cs index dd46d2a..8e46d52 100644 --- a/WindowsInstallerLib/src/ProcessManager.cs +++ b/WindowsInstallerLib/src/ProcessManager.cs @@ -143,6 +143,14 @@ internal static int StartDiskPartProcess(int DiskNumber, string EfiDrive, string return ExitCode; } + internal static int StartDiskPartProcessThreaded(int DiskNumber, string EfiDrive, string DestinationDrive) + { + ThreadManager.CreateThread( + () => StartDiskPartProcess(DiskNumber, EfiDrive, DestinationDrive) + ); + return ExitCode; + } + /// /// Starts a new process to execute the Deployment Image Servicing and Management (DISM) tool with the specified /// arguments. From 7eb42d080440ef8944d2920dec540802b7e22388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gonz=C3=A1lez=20Mart=C3=ADn?= <158048821+felgmar@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:25:05 +0100 Subject: [PATCH 5/6] WindowsInstallerLib: add UseMultiThreading parameter --- WindowsInstallerLib/src/InstallerManager.cs | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/WindowsInstallerLib/src/InstallerManager.cs b/WindowsInstallerLib/src/InstallerManager.cs index 18a9e6d..712e8d2 100644 --- a/WindowsInstallerLib/src/InstallerManager.cs +++ b/WindowsInstallerLib/src/InstallerManager.cs @@ -37,6 +37,7 @@ public struct Parameters(string DestinationDrive, public string ImageFilePath { get; set; } = ImageFilePath; public bool InstallExtraDrivers { get; set; } = InstallExtraDrivers; public string FirmwareType { get; set; } = FirmwareType; + public bool UseMultiThreading { get; set; } = false; } /// @@ -61,6 +62,40 @@ public sealed class InstallerManager /// Thrown if the firmware type cannot be determined or is invalid. public static void Configure(ref Parameters parameters) { + #region UseMultiThreading + Console.WriteLine("\nDo you want to enable multithreading?: "); + string? p_UseMultiThreading = Console.ReadLine(); + + if (!string.IsNullOrWhiteSpace(p_UseMultiThreading)) + { + try + { + parameters.UseMultiThreading = p_UseMultiThreading.ToLowerInvariant() switch + { + "yes" or "y" or "true" => true, + "no" or "n" or "false" => false, + _ => throw new ArgumentException("Invalid input for multithreading option. Please type 'yes' or 'no'.") + }; + } + catch (Exception) + { + throw; + } + } + + switch (parameters.UseMultiThreading) + { + case true: + parameters.UseMultiThreading = true; + Console.WriteLine($"\nMultithreading is enabled.", ConsoleColor.Yellow); + break; + case false: + parameters.UseMultiThreading = false; + Console.WriteLine($"\nMultithreading is disabled.", ConsoleColor.Yellow); + break; + } + #endregion + #region DestinationDrive if (string.IsNullOrEmpty(parameters.DestinationDrive) || string.IsNullOrWhiteSpace(parameters.DestinationDrive)) From 7e7902cd8172dee4a6f719d800712412311caa18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gonz=C3=A1lez=20Mart=C3=ADn?= <158048821+felgmar@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:31:48 +0100 Subject: [PATCH 6/6] ConsoleApp: add "/multithreaded" argument --- ConsoleApp/src/ArgumentParser.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ConsoleApp/src/ArgumentParser.cs b/ConsoleApp/src/ArgumentParser.cs index 68f5c51..621e566 100644 --- a/ConsoleApp/src/ArgumentParser.cs +++ b/ConsoleApp/src/ArgumentParser.cs @@ -64,6 +64,9 @@ internal static void ParseArgs(ref Parameters parameters, string[] args) case "/firmwaretype": parameters.FirmwareType = args[Array.IndexOf(args, arg) + 1].ToUpperInvariant(); continue; + case "/multithreaded": + parameters.UseMultiThreading = args[Array.IndexOf(args, arg) + 1].Equals("TRUE", StringComparison.OrdinalIgnoreCase); + continue; } } #if DEBUG @@ -76,6 +79,7 @@ internal static void ParseArgs(ref Parameters parameters, string[] args) Console.WriteLine($" Image File Path: {parameters.ImageFilePath}"); Console.WriteLine($" Install Extra Drivers: {parameters.InstallExtraDrivers}"); Console.WriteLine($" Firmware Type: {parameters.FirmwareType}"); + Console.WriteLine($" Multithreaded: {parameters.UseMultiThreading}"); Console.WriteLine("Press any key to continue..."); Console.ReadKey(); #endif