diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 5bba0978..a9427652 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -7,6 +7,7 @@ using Bloxstrap.Resources; using Bloxstrap.AppData; using System.Windows.Shell; +using Bloxstrap.UI.Elements.Bootstrapper.Base; namespace Bloxstrap { @@ -14,8 +15,10 @@ public class Bootstrapper { #region Properties private const int ProgressBarMaximum = 10000; - private const double TaskbarProgressMaximum = 1; // this can not be changed. keep it at 1. - + + private const double TaskbarProgressMaximumWpf = 1; // this can not be changed. keep it at 1. + private const int TaskbarProgressMaximumWinForms = WinFormsDialogBase.TaskbarProgressMaximum; + private const string AppSettings = "\r\n" + "\r\n" + @@ -74,6 +77,7 @@ private int _distributionSize private bool _isInstalling = false; private double _progressIncrement; private double _taskbarProgressIncrement; + private double _taskbarProgressMaximum; private long _totalDownloadedBytes = 0; private int _packagesExtracted = 0; private bool _cancelFired = false; @@ -120,7 +124,7 @@ private void UpdateProgressBar() // taskbar progress double taskbarProgressValue = _taskbarProgressIncrement * _totalDownloadedBytes; - taskbarProgressValue = Math.Clamp(taskbarProgressValue, 0, TaskbarProgressMaximum); + taskbarProgressValue = Math.Clamp(taskbarProgressValue, 0, _taskbarProgressMaximum); Dialog.TaskbarProgressValue = taskbarProgressValue; } @@ -631,7 +635,13 @@ private async Task InstallLatestVersion() // compute total bytes to download int totalSize = _versionPackageManifest.Sum(package => package.PackedSize); _progressIncrement = (double)ProgressBarMaximum / totalSize; - _taskbarProgressIncrement = (double)TaskbarProgressMaximum / totalSize; + + if (Dialog is WinFormsDialogBase) + _taskbarProgressMaximum = (double)TaskbarProgressMaximumWinForms; + else + _taskbarProgressMaximum = (double)TaskbarProgressMaximumWpf; + + _taskbarProgressIncrement = _taskbarProgressMaximum / (double)totalSize; } foreach (Package package in _versionPackageManifest) diff --git a/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs b/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs index d3005de3..db2814bc 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs @@ -7,6 +7,8 @@ namespace Bloxstrap.UI.Elements.Bootstrapper.Base { public class WinFormsDialogBase : Form, IBootstrapperDialog { + public const int TaskbarProgressMaximum = 100; + public Bloxstrap.Bootstrapper? Bootstrapper { get; set; } private bool _isClosing; @@ -73,10 +75,8 @@ public TaskbarItemProgressState TaskbarProgressState get => _taskbarProgressState; set { - if (InvokeRequired) - Invoke(() => _taskbarProgressState = value); - else - _taskbarProgressState = value; + _taskbarProgressState = value; + TaskbarProgress.SetProgressState(Process.GetCurrentProcess().MainWindowHandle, value); } } @@ -85,10 +85,8 @@ public double TaskbarProgressValue get => _taskbarProgressValue; set { - if (InvokeRequired) - Invoke(() => _taskbarProgressValue = value); - else - _taskbarProgressValue = value; + _taskbarProgressValue = value; + TaskbarProgress.SetProgressValue(Process.GetCurrentProcess().MainWindowHandle, (int)value, TaskbarProgressMaximum); } } diff --git a/Bloxstrap/UI/Utility/TaskbarProgress.cs b/Bloxstrap/UI/Utility/TaskbarProgress.cs new file mode 100644 index 00000000..7cc7a698 --- /dev/null +++ b/Bloxstrap/UI/Utility/TaskbarProgress.cs @@ -0,0 +1,90 @@ +using System.Runtime.InteropServices; +using System.Windows.Shell; + +namespace Bloxstrap.UI.Utility +{ + // Modified from https://github.com/PowerShell/PSReadLine/blob/e9122d38e932614393ff61faf57d6518990d7226/PSReadLine/PlatformWindows.cs#L704 + internal static class TaskbarProgress + { + private enum TaskbarStates + { + NoProgress = 0, + Indeterminate = 0x1, + Normal = 0x2, + Error = 0x4, + Paused = 0x8, + } + + [ComImport()] + [Guid("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface ITaskbarList3 + { + // ITaskbarList + [PreserveSig] + int HrInit(); + + [PreserveSig] + int AddTab(IntPtr hwnd); + + [PreserveSig] + int DeleteTab(IntPtr hwnd); + + [PreserveSig] + int ActivateTab(IntPtr hwnd); + + [PreserveSig] + int SetActiveAlt(IntPtr hwnd); + + // ITaskbarList2 + [PreserveSig] + int MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + // ITaskbarList3 + [PreserveSig] + int SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal); + + [PreserveSig] + int SetProgressState(IntPtr hwnd, TaskbarStates state); + + // N.B. for copy/pasters: we've left out the rest of the ITaskbarList3 methods... + } + + [ComImport()] + [Guid("56fdf344-fd6d-11d0-958a-006097c9a090")] + [ClassInterface(ClassInterfaceType.None)] + private class TaskbarInstance + { + } + + private static Lazy _taskbarInstance = new Lazy(() => (ITaskbarList3)new TaskbarInstance()); + + private static TaskbarStates ConvertEnum(TaskbarItemProgressState state) + { + return state switch + { + TaskbarItemProgressState.None => TaskbarStates.NoProgress, + TaskbarItemProgressState.Indeterminate => TaskbarStates.Indeterminate, + TaskbarItemProgressState.Normal => TaskbarStates.Normal, + TaskbarItemProgressState.Error => TaskbarStates.Error, + TaskbarItemProgressState.Paused => TaskbarStates.Paused, + _ => throw new Exception($"Unrecognised TaskbarItemProgressState: {state}") + }; + } + + private static int SetProgressState(IntPtr windowHandle, TaskbarStates taskbarState) + { + return _taskbarInstance.Value.SetProgressState(windowHandle, taskbarState); + } + + public static int SetProgressState(IntPtr windowHandle, TaskbarItemProgressState taskbarState) + { + return SetProgressState(windowHandle, ConvertEnum(taskbarState)); + } + + public static int SetProgressValue(IntPtr windowHandle, int progressValue, int progressMax) + { + return _taskbarInstance.Value.SetProgressValue(windowHandle, (ulong)progressValue, (ulong)progressMax); + } + } +}