| | |
| | | /****************************************************************************
|
| | | **
|
| | | ** Copyright (C) 2016 The Qt Company Ltd.
|
| | | ** Copyright (C) 2022 The Qt Company Ltd.
|
| | | ** Contact: https://www.qt.io/licensing/
|
| | | **
|
| | | ** This file is part of the Qt VS Tools.
|
| | |
| | | **
|
| | | ****************************************************************************/
|
| | |
|
| | | using EnvDTE;
|
| | | using System;
|
| | | using System.Collections.Concurrent;
|
| | | using System.Diagnostics;
|
| | | using System.Linq;
|
| | | using System.Threading;
|
| | | using Thread = System.Threading.Thread;
|
| | | using System.Windows.Forms;
|
| | | using System.Threading.Tasks;
|
| | | using Microsoft.VisualStudio.Shell;
|
| | | using Microsoft.VisualStudio.Threading;
|
| | | using QtVsTools.VisualStudio;
|
| | |
|
| | | using Task = System.Threading.Tasks.Task;
|
| | |
|
| | | namespace QtVsTools.Core
|
| | | {
|
| | | using VisualStudio;
|
| | |
|
| | | public static class Messages
|
| | | {
|
| | | private static OutputWindow Window { get; set; }
|
| | | private static OutputWindowPane Pane { get; set; }
|
| | |
|
| | | private static OutputWindowPane _BuildPane;
|
| | | private static OutputWindowPane BuildPane
|
| | | {
|
| | | get
|
| | | {
|
| | | return _BuildPane ?? (_BuildPane = Window.OutputWindowPanes.Cast<OutputWindowPane>()
|
| | | .Where(pane => pane.Guid == "{1BD8A850-02D1-11D1-BEE7-00A0C913D1F8}")
|
| | | .FirstOrDefault());
|
| | | }
|
| | | }
|
| | | private static readonly string PaneName = "Qt VS Tools";
|
| | | private static readonly Guid PaneGuid = new Guid("8f6a1e44-fa0b-49e5-9934-1c050555350e");
|
| | |
|
| | | /// <summary>
|
| | | /// Show a message on the output pane.
|
| | |
| | | FlushMessages();
|
| | | }
|
| | |
|
| | | static void OutputWindowPane_Print(string text)
|
| | | public static void Log(this Exception exception, bool clear = false, bool activate = false)
|
| | | {
|
| | | OutputWindowPane_Init();
|
| | | Pane.OutputString(text + "\r\n");
|
| | | // show buildPane if a build is in progress
|
| | | if (Dte.Solution.SolutionBuild.BuildState == vsBuildState.vsBuildStateInProgress)
|
| | | BuildPane?.Activate();
|
| | | msgQueue.Enqueue(new Msg()
|
| | | {
|
| | | Clear = clear,
|
| | | Text = ExceptionToString(exception),
|
| | | Activate = activate
|
| | | });
|
| | | FlushMessages();
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | |
| | | FlushMessages();
|
| | | }
|
| | |
|
| | | static void OutputWindowPane_Activate()
|
| | | static async Task OutputWindowPane_ActivateAsync()
|
| | | {
|
| | | OutputWindowPane_Init();
|
| | | Pane?.Activate();
|
| | | await OutputWindowPane_InitAsync();
|
| | | await Pane?.ActivateAsync();
|
| | | }
|
| | |
|
| | | private static string ExceptionToString(System.Exception e)
|
| | | private static string ExceptionToString(System.Exception exception)
|
| | | {
|
| | | return e.Message + "\r\n" + "(" + e.StackTrace.Trim() + ")";
|
| | | return $"An exception ({exception.GetType().Name}) occurred.\r\n"
|
| | | + $"Message:\r\n {exception.Message}\r\n"
|
| | | + $"Stack Trace:\r\n {exception.StackTrace.Trim()}\r\n";
|
| | | }
|
| | |
|
| | | private static readonly string ErrorString = SR.GetString("Messages_ErrorOccured");
|
| | | private static readonly string WarningString = SR.GetString("Messages_Warning");
|
| | | private static readonly string SolutionString = SR.GetString("Messages_SolveProblem");
|
| | |
|
| | | static public void DisplayCriticalErrorMessage(System.Exception e)
|
| | | {
|
| | | MessageBox.Show(ErrorString +
|
| | | ExceptionToString(e),
|
| | | SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
|
| | | }
|
| | |
|
| | | static public void DisplayCriticalErrorMessage(string msg)
|
| | | public static void DisplayCriticalErrorMessage(string msg)
|
| | | {
|
| | | MessageBox.Show(ErrorString +
|
| | | msg,
|
| | | SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
|
| | | }
|
| | |
|
| | | static public void DisplayErrorMessage(System.Exception e)
|
| | | public static void DisplayErrorMessage(System.Exception e)
|
| | | {
|
| | | MessageBox.Show(ErrorString +
|
| | | ExceptionToString(e),
|
| | | MessageBox.Show(ExceptionToString(e),
|
| | | SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
|
| | | }
|
| | |
|
| | | static public void DisplayErrorMessage(string msg)
|
| | | public static void DisplayErrorMessage(string msg)
|
| | | {
|
| | | MessageBox.Show(ErrorString +
|
| | | msg,
|
| | | SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
|
| | | }
|
| | |
|
| | | static public void DisplayWarningMessage(System.Exception e, string solution)
|
| | | public static void DisplayWarningMessage(System.Exception e, string solution)
|
| | | {
|
| | | MessageBox.Show(WarningString +
|
| | | ExceptionToString(e) +
|
| | |
| | | SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
| | | }
|
| | |
|
| | | static public void DisplayWarningMessage(string msg)
|
| | | public static void DisplayWarningMessage(string msg)
|
| | | {
|
| | | MessageBox.Show(WarningString +
|
| | | msg,
|
| | |
| | | FlushMessages();
|
| | | }
|
| | |
|
| | | static void OutputWindowPane_Clear()
|
| | | static async Task OutputWindowPane_ClearAsync()
|
| | | {
|
| | | OutputWindowPane_Init();
|
| | | Pane?.Clear();
|
| | | await OutputWindowPane_InitAsync();
|
| | | await Pane?.ClearAsync();
|
| | | }
|
| | |
|
| | | class Msg
|
| | |
| | | public bool Activate { get; set; } = false;
|
| | | }
|
| | |
|
| | | static bool shuttingDown = false;
|
| | | static ConcurrentQueue<Msg> msgQueue = new ConcurrentQueue<Msg>();
|
| | | static DTE Dte { get; set; } = null;
|
| | | static readonly ConcurrentQueue<Msg> msgQueue = new ConcurrentQueue<Msg>();
|
| | |
|
| | | private static void OnBeginShutdown()
|
| | | private static async Task OutputWindowPane_InitAsync()
|
| | | {
|
| | | shuttingDown = true;
|
| | | }
|
| | |
|
| | | private static void OutputWindowPane_Init()
|
| | | {
|
| | | if (Dte == null)
|
| | | Dte = VsServiceProvider.GetService<DTE>();
|
| | | var t = Stopwatch.StartNew();
|
| | | while (Pane == null && t.ElapsedMilliseconds < 5000) {
|
| | | try {
|
| | | Window = Dte.Windows.Item(Constants.vsWindowKindOutput).Object as OutputWindow;
|
| | | Pane = Window?.OutputWindowPanes.Add(SR.GetString("Resources_QtVsTools"));
|
| | | } catch {
|
| | | }
|
| | | try {
|
| | | if (Pane == null)
|
| | | Thread.Yield();
|
| | | Pane = await OutputWindowPane.CreateAsync(PaneName, PaneGuid);
|
| | | } catch (Exception ex) {
|
| | | System.Diagnostics.Debug.WriteLine(ex);
|
| | | }
|
| | | Dte.Events.DTEEvents.OnBeginShutdown += OnBeginShutdown;
|
| | | }
|
| | |
|
| | | public static JoinableTaskFactory JoinableTaskFactory { get; set; }
|
| | |
|
| | | static readonly object staticCriticalSection = new object();
|
| | | static Task FlushTask { get; set; }
|
| | | static EventWaitHandle MessageReady { get; set; }
|
| | |
| | | MessageReady = new EventWaitHandle(false, EventResetMode.AutoReset);
|
| | | FlushTask = Task.Run(async () =>
|
| | | {
|
| | | while (!shuttingDown) {
|
| | | var package = VsServiceProvider.Instance as Package;
|
| | | while (!package.Zombied) {
|
| | | if (!await MessageReady.ToTask(3000))
|
| | | continue;
|
| | | while (!msgQueue.IsEmpty) {
|
| | | Msg msg;
|
| | | if (!msgQueue.TryDequeue(out msg)) {
|
| | | if (!msgQueue.TryDequeue(out Msg msg)) {
|
| | | await Task.Yield();
|
| | | continue;
|
| | | }
|
| | | ////////////////////////////////////////////////////////////////////
|
| | | // Switch to main (UI) thread
|
| | | await JoinableTaskFactory.SwitchToMainThreadAsync();
|
| | | if (msg.Clear)
|
| | | OutputWindowPane_Clear();
|
| | | await OutputWindowPane_ClearAsync();
|
| | | if (msg.Text != null)
|
| | | OutputWindowPane_Print(msg.Text);
|
| | | await OutputWindowPane_PrintAsync(msg.Text);
|
| | | if (msg.Activate)
|
| | | OutputWindowPane_Activate();
|
| | | ////////////////////////////////////////////////////////////////////
|
| | | // Switch to background thread
|
| | | await TaskScheduler.Default;
|
| | | await OutputWindowPane_ActivateAsync();
|
| | | }
|
| | | }
|
| | | });
|
| | |
| | | }
|
| | | MessageReady.Set();
|
| | | }
|
| | |
|
| | | static async Task OutputWindowPane_PrintAsync(string text)
|
| | | {
|
| | | var active = await OutputWindowPane.GetActiveAsync();
|
| | |
|
| | | await OutputWindowPane_InitAsync();
|
| | | await Pane.PrintAsync(text);
|
| | |
|
| | | (active?.ActivateAsync()).Forget();
|
| | | }
|
| | | }
|
| | | }
|