Task DoDecompile(DecompilationContext context, int outputLengthLimit) { return(RunWithCancellation( delegate(CancellationToken ct) { // creation of the background task context.Options.CancellationToken = ct; return DecompileAsync(context, outputLengthLimit); }) .Then( delegate(AvaloniaEditTextOutput textOutput) { // handling the result ShowOutput(textOutput, context.Language.SyntaxHighlighting, context.Options.TextViewState); decompiledNodes = context.TreeNodes; }) .Catch <Exception>(exception => { textEditor.SyntaxHighlighting = null; Debug.WriteLine("Decompiler crashed: " + exception.ToString()); AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); if (exception is OutputLengthExceededException) { WriteOutputLengthExceededMessage(output, context, outputLengthLimit == DefaultOutputLengthLimit); } else { output.WriteLine(exception.ToString()); } ShowOutput(output); decompiledNodes = context.TreeNodes; })); }
Task <AvaloniaEditTextOutput> SaveToDiskAsync(DecompilationContext context, string fileName) { TaskCompletionSource <AvaloniaEditTextOutput> tcs = new TaskCompletionSource <AvaloniaEditTextOutput>(); Thread thread = new Thread(new ThreadStart( delegate { try { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); using (StreamWriter w = new StreamWriter(fileName)) { try { DecompileNodes(context, new PlainTextOutput(w)); } catch (OperationCanceledException) { w.WriteLine(); w.WriteLine("Decompiled was cancelled."); throw; } } stopwatch.Stop(); AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); output.WriteLine("Decompilation complete in " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds."); output.WriteLine(); output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.WriteLine(); tcs.SetResult(output); } catch (OperationCanceledException) { tcs.SetCanceled(); #if DEBUG } catch (AggregateException ex) { tcs.SetException(ex); #else } catch (Exception ex) { tcs.SetException(ex); #endif } })); thread.Start(); return(tcs.Task); }
/// <summary> /// Starts the decompilation of the given nodes. /// The result will be saved to the given file name. /// </summary> void SaveToDisk(DecompilationContext context, string fileName) { RunWithCancellation( delegate(CancellationToken ct) { context.Options.CancellationToken = ct; return(SaveToDiskAsync(context, fileName)); }) .Then(output => ShowOutput(output)) .Catch((Exception ex) => { textEditor.SyntaxHighlighting = null; Debug.WriteLine("Decompiler crashed: " + ex.ToString()); // Unpack aggregate exceptions as long as there's only a single exception: // (assembly load errors might produce nested aggregate exceptions) AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); output.WriteLine(ex.ToString()); ShowOutput(output); }).HandleExceptions(); }
/// <summary> /// Switches the GUI into "waiting" mode, then calls <paramref name="taskCreation"/> to create /// the task. /// If another task is started before the previous task finishes running, the previous task is cancelled. /// </summary> public Task <T> RunWithCancellation <T>(Func <CancellationToken, Task <T> > taskCreation) { if (waitAdorner.IsVisible != true) { waitAdorner.IsVisible = true; // Work around a WPF bug by setting IsIndeterminate only while the progress bar is visible. // https://github.com/icsharpcode/ILSpy/issues/593 progressBar.IsIndeterminate = true; waitAdorner.Opacity = 1; //TODO: animation //waitAdorner.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.Stop)); // TODO: taskbar progress //var taskBar = MainWindow.Instance.TaskbarItemInfo; //if (taskBar != null) { // taskBar.ProgressState = Avalonia.Shell.TaskbarItemProgressState.Indeterminate; //} } CancellationTokenSource previousCancellationTokenSource = currentCancellationTokenSource; var myCancellationTokenSource = new CancellationTokenSource(); currentCancellationTokenSource = myCancellationTokenSource; // cancel the previous only after current was set to the new one (avoid that the old one still finishes successfully) if (previousCancellationTokenSource != null) { previousCancellationTokenSource.Cancel(); } var tcs = new TaskCompletionSource <T>(); Task <T> task; try { task = taskCreation(myCancellationTokenSource.Token); } catch (OperationCanceledException) { task = TaskHelper.FromCancellation <T>(); } catch (Exception ex) { task = TaskHelper.FromException <T>(ex); } Action continuation = delegate { try { if (currentCancellationTokenSource == myCancellationTokenSource) { currentCancellationTokenSource = null; waitAdorner.IsVisible = false; progressBar.IsIndeterminate = false; // TODO: taskbar progress //var taskBar = MainWindow.Instance.TaskbarItemInfo; //if (taskBar != null) { // taskBar.ProgressState = TaskbarItemProgressState.None; //} if (task.IsCanceled) { AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); output.WriteLine("The operation was canceled."); ShowOutput(output); } tcs.SetFromTask(task); } else { tcs.SetCanceled(); } } finally { myCancellationTokenSource.Dispose(); } }; task.ContinueWith(delegate { Dispatcher.UIThread.InvokeAsync(continuation, DispatcherPriority.Normal); }); return(tcs.Task); }