/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Runtime.ExceptionServices; using System.Windows.Threading; namespace dnSpy.Contracts.Scripting { /// /// Executes code on the UI thread /// public static class UIUtils { /// /// Executes on the UI thread and then returns /// /// UI dispatcher /// Action public static void UI(this Dispatcher dispatcher, Action a) { if (dispatcher.CheckAccess()) { a(); return; } System.Diagnostics.Debugger.NotifyOfCrossThreadDependency(); ExceptionDispatchInfo? exInfo = null; dispatcher.Invoke(new Action(() => { try { a(); } catch (Exception ex) { exInfo = ExceptionDispatchInfo.Capture(ex); return; } }), DispatcherPriority.Send); if (exInfo is not null) exInfo.Throw(); } /// /// Executes on the UI thread and returns the result /// /// Return type /// UI dispatcher /// Func /// public static T UI(this Dispatcher dispatcher, Func f) { if (dispatcher.CheckAccess()) return f(); System.Diagnostics.Debugger.NotifyOfCrossThreadDependency(); ExceptionDispatchInfo? exInfo = null; var res = (T)dispatcher.Invoke(new Func(() => { try { return f(); } catch (Exception ex) { exInfo = ExceptionDispatchInfo.Capture(ex); return default!; } }), DispatcherPriority.Send); if (exInfo is not null) exInfo.Throw(); return res; } /// /// Returns the result of an . is /// only called on the UI thread. /// /// Type to return /// UI dispatcher /// Called on the UI thread to return the result /// public static IEnumerable UIIter(this Dispatcher dispatcher, Func> getIter) { if (dispatcher.CheckAccess()) { foreach (var o in getIter()) yield return o; yield break; } System.Diagnostics.Debugger.NotifyOfCrossThreadDependency(); IEnumerator? enumerator = null; for (;;) { bool canContinue = false; ExceptionDispatchInfo? exInfo = null; var res = (T)dispatcher.Invoke(new Func(() => { try { if (enumerator is null) enumerator = getIter().GetEnumerator(); if (!(canContinue = enumerator.MoveNext())) return default!; return enumerator.Current; } catch (Exception ex) { canContinue = false; exInfo = ExceptionDispatchInfo.Capture(ex); return default!; } }), DispatcherPriority.Send); if (exInfo is not null) exInfo.Throw(); if (!canContinue) break; yield return res; } } } }