OperationWithProgressBase.cs (4125B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="OperationWithProgressBase.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 7 namespace Microsoft.WinGet.Client.Engine.Helpers 8 { 9 using System; 10 using System.Runtime.InteropServices; 11 using System.Threading.Tasks; 12 using Microsoft.WinGet.Common.Command; 13 using Microsoft.WinGet.Resources; 14 using Windows.Foundation; 15 16 /// <summary> 17 /// Base class for async operations with progress. 18 /// </summary> 19 /// <typeparam name="TOperationResult">The operation result.</typeparam> 20 /// <typeparam name="TProgressData">Progress data.</typeparam> 21 internal abstract class OperationWithProgressBase<TOperationResult, TProgressData> 22 { 23 private static bool isProgressEnabled; 24 25 static OperationWithProgressBase() 26 { 27 // Progress on arm64 will produce an AV because there's an OS bug where marshaling structs over a certain size fail. 28 // Fix is in 10.0.26068.0, for build before that disable progress. 29 if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) 30 { 31 var minWindowsVersion = new Version(10, 0, 26068, 0); 32 var osVersion = Environment.OSVersion.Version; 33 isProgressEnabled = osVersion.CompareTo(minWindowsVersion) >= 0; 34 } 35 else 36 { 37 isProgressEnabled = true; 38 } 39 } 40 41 /// <summary> 42 /// Initializes a new instance of the <see cref="OperationWithProgressBase{TOperationResult, TProgressData}"/> class. 43 /// </summary> 44 /// <param name="pwshCmdlet">A <see cref="PowerShellCmdlet" /> instance.</param> 45 /// <param name="activity">Activity.</param> 46 public OperationWithProgressBase( 47 PowerShellCmdlet pwshCmdlet, 48 string activity) 49 { 50 this.PwshCmdlet = pwshCmdlet; 51 this.ActivityId = pwshCmdlet.GetNewProgressActivityId(); 52 this.Activity = activity; 53 } 54 55 /// <summary> 56 /// Gets the PowerShellCmdlet. 57 /// </summary> 58 protected PowerShellCmdlet PwshCmdlet { get; } 59 60 /// <summary> 61 /// Gets the progress activity id. 62 /// </summary> 63 protected int ActivityId { get; } 64 65 /// <summary> 66 /// Gets the activity. 67 /// </summary> 68 protected string Activity { get; } 69 70 /// <summary> 71 /// Progress callback. 72 /// </summary> 73 /// <param name="operation">Async operation in progress.</param> 74 /// <param name="progress">Progress data.</param> 75 public abstract void Progress(IAsyncOperationWithProgress<TOperationResult, TProgressData> operation, TProgressData progress); 76 77 /// <summary> 78 /// Starts the operation and executes it as task. 79 /// Supports cancellation. 80 /// </summary> 81 /// <param name="func">Lambda with operation.</param> 82 /// <returns>TOperationReturn.</returns> 83 public async Task<TOperationResult> ExecuteAsync(Func<IAsyncOperationWithProgress<TOperationResult, TProgressData>> func) 84 { 85 var operation = func(); 86 87 if (isProgressEnabled) 88 { 89 operation.Progress = this.Progress; 90 } 91 92 try 93 { 94 return await operation.AsTask(this.PwshCmdlet.GetCancellationToken()); 95 } 96 finally 97 { 98 this.Complete(); 99 } 100 } 101 102 /// <summary> 103 /// Completes progress for this activity. 104 /// </summary> 105 protected virtual void Complete() 106 { 107 this.PwshCmdlet.CompleteProgress(this.ActivityId, this.Activity, Resources.Completed, true); 108 } 109 } 110 }