diff --git a/source/Cosmos.VS.Windows/CosmosMenuCmdSet.cs b/source/Cosmos.VS.Windows/CosmosMenuCmdSet.cs index 30e2f45bc..21320fc83 100644 --- a/source/Cosmos.VS.Windows/CosmosMenuCmdSet.cs +++ b/source/Cosmos.VS.Windows/CosmosMenuCmdSet.cs @@ -1,8 +1,10 @@ using System; using System.ComponentModel.Design; using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using Task = System.Threading.Tasks.Task; using Cosmos.VS.Windows.ToolWindows; @@ -16,86 +18,79 @@ namespace Cosmos.VS.Windows public const int CosmosInternalCmdID = 0x0103; public const int CosmosShowAllCmdID = 0x0104; - private readonly CosmosWindowsPackage package; + private readonly CosmosWindowsPackage _package; private CosmosMenuCmdSet(CosmosWindowsPackage package) { - this.package = package ?? throw new ArgumentNullException(nameof(package)); + _package = package ?? throw new ArgumentNullException(nameof(package)); - AddCommand(CosmosAssemblyCmdID, ShowWindowAssembly); - AddCommand(CosmosRegistersCmdID, ShowWindowRegisters); - AddCommand(CosmosStackCmdID, ShowWindowStack); - AddCommand(CosmosInternalCmdID, ShowWindowInternal); - AddCommand(CosmosShowAllCmdID, ShowWindowAll); + AddCommand(CosmosAssemblyCmdID, ShowWindowAssemblyAsync); + AddCommand(CosmosRegistersCmdID, ShowWindowRegistersAsync); + AddCommand(CosmosStackCmdID, ShowWindowStackAsync); + AddCommand(CosmosInternalCmdID, ShowWindowInternalAsync); + AddCommand(CosmosShowAllCmdID, ShowWindowAllAsync); } private void AddCommand(int cmdId, EventHandler handler) { - OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService; - if (commandService != null) + if (ServiceProvider.GetService(typeof(IMenuCommandService)) is OleMenuCommandService commandService) { var menuCommandID = new CommandID(Guids.CosmosMenuCmdSetGuid, cmdId); var menuItem = new MenuCommand(handler, menuCommandID); + commandService.AddCommand(menuItem); } } + private void AddCommand(int cmdId, AsyncEventHandler handler) => + AddCommand(cmdId, (EventHandler)((sender, e) => handler?.InvokeAsync(sender, e))); + public static CosmosMenuCmdSet Instance { get; private set; } - private IServiceProvider ServiceProvider => package; + private IServiceProvider ServiceProvider => _package; public static void Initialize(CosmosWindowsPackage package) { Instance = new CosmosMenuCmdSet(package); } - private void ShowWindow(Type aWindowType) + private async Task ShowWindowAsync(Type aWindowType) { - var xWindow = package.FindWindow(aWindowType); + await _package.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var xWindow = await _package.FindWindowAsync(aWindowType); var xFrame = (IVsWindowFrame)xWindow.Frame; + ErrorHandler.ThrowOnFailure(xFrame.Show()); } - private void ShowChannelWindow(Type aWindowType) + private async Task ShowChannelWindowAsync(Type aWindowType) { - var xWindow = package.FindChannelWindow(aWindowType); + await _package.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var xWindow = await _package.FindChannelWindowAsync(aWindowType); var xFrame = (IVsWindowFrame)xWindow.Frame; + ErrorHandler.ThrowOnFailure(xFrame.Show()); } - private void ShowWindowAssembly(object aCommand, EventArgs e) - { - ShowWindow(typeof(AssemblyToolWindow)); - } + private Task ShowWindowAssemblyAsync(object sender, EventArgs e) => ShowWindowAsync(typeof(AssemblyToolWindow)); - private void ShowWindowInternal(object aCommand, EventArgs e) - { - ShowWindow(typeof(InternalTW)); - } + private Task ShowWindowInternalAsync(object sender, EventArgs e) => ShowWindowAsync(typeof(InternalTW)); - private void ShowWindowRegisters(object aCommand, EventArgs e) - { - ShowWindow(typeof(RegistersToolWindow)); - } + private Task ShowWindowRegistersAsync(object sender, EventArgs e) => ShowWindowAsync(typeof(RegistersToolWindow)); - private void ShowWindowStack(object aCommand, EventArgs e) - { - ShowWindow(typeof(StackTW)); - } + private Task ShowWindowStackAsync(object sender, EventArgs e) => ShowWindowAsync(typeof(StackTW)); - private void ShowWindowConsole(object aCommand, EventArgs e) - { - ShowChannelWindow(typeof(ConsoleTW)); - } - - private void ShowWindowAll(object aCommand, EventArgs e) - { - ShowWindowAssembly(aCommand, e); - ShowWindowRegisters(aCommand, e); - ShowWindowStack(aCommand, e); - //ShowWindowConsole(aCommand, e); - // Dont show Internal Window, most Cosmos users wont use it. - } + private Task ShowWindowConsoleAsync(object sender, EventArgs e) => ShowChannelWindowAsync(typeof(ConsoleTW)); + private Task ShowWindowAllAsync(object sender, EventArgs e) => + Task.WhenAll( + ShowWindowAssemblyAsync(sender, e), + ShowWindowRegistersAsync(sender, e), + ShowWindowStackAsync(sender, e) + //ShowWindowConsole(sender, e) + // Dont show Internal Window, most Cosmos users wont use it. + ); } } diff --git a/source/Cosmos.VS.Windows/CosmosWindowsPackage.cs b/source/Cosmos.VS.Windows/CosmosWindowsPackage.cs index cc59f0a56..49017edc3 100644 --- a/source/Cosmos.VS.Windows/CosmosWindowsPackage.cs +++ b/source/Cosmos.VS.Windows/CosmosWindowsPackage.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading; -using System.Windows.Threading; +using System.Threading.Tasks; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -48,7 +48,7 @@ namespace Cosmos.VS.Windows // So instead we use a stack and a timer to poll it for data. mTimer = new Timer(100); mTimer.AutoReset = true; - mTimer.Elapsed += ProcessMessage; + mTimer.Elapsed += (sender, e) => JoinableTaskFactory.RunAsync(() => ProcessMessageAsync(sender, e)); mTimer.Start(); mPipeDown = new PipeServer(Pipes.DownName); @@ -86,8 +86,8 @@ namespace Cosmos.VS.Windows base.Dispose(disposing); } - - void ProcessMessage(object sender, EventArgs e) + + private async Task ProcessMessageAsync(object sender, EventArgs e) { ushort xCmd; byte[] xMsg; @@ -111,47 +111,47 @@ namespace Cosmos.VS.Windows break; case Debugger2Windows.Stack: - UpdateWindow(typeof(StackTW), "STACK", xMsg); + await UpdateWindowAsync(typeof(StackTW), "STACK", xMsg); break; case Debugger2Windows.Frame: - UpdateWindow(typeof(StackTW), "FRAME", xMsg); + await UpdateWindowAsync(typeof(StackTW), "FRAME", xMsg); break; case Debugger2Windows.Registers: - UpdateWindow(typeof(RegistersToolWindow), null, xMsg); + await UpdateWindowAsync(typeof(RegistersToolWindow), null, xMsg); break; case Debugger2Windows.Quit: break; case Debugger2Windows.AssemblySource: - UpdateWindow(typeof(AssemblyToolWindow), null, xMsg); + await UpdateWindowAsync(typeof(AssemblyToolWindow), null, xMsg); break; case Debugger2Windows.PongVSIP: - UpdateWindow(typeof(InternalTW), null, Encoding.UTF8.GetBytes("Pong from VSIP")); + await UpdateWindowAsync(typeof(InternalTW), null, Encoding.UTF8.GetBytes("Pong from VSIP")); break; case Debugger2Windows.PongDebugStub: - UpdateWindow(typeof(InternalTW), null, Encoding.UTF8.GetBytes("Pong from DebugStub")); + await UpdateWindowAsync(typeof(InternalTW), null, Encoding.UTF8.GetBytes("Pong from DebugStub")); break; case Debugger2Windows.OutputPane: - System.Windows.Application.Current.Dispatcher.Invoke( - () => Global.OutputPane.OutputString(Encoding.UTF8.GetString(xMsg)), - DispatcherPriority.Normal); + await JoinableTaskFactory.SwitchToMainThreadAsync(); + Global.OutputPane.OutputString(Encoding.UTF8.GetString(xMsg)); break; case Debugger2Windows.OutputClear: - System.Windows.Application.Current.Dispatcher.Invoke( - () => { Global.OutputPane.Clear(); StateStorer.ClearState(); }, DispatcherPriority.Normal); + await JoinableTaskFactory.SwitchToMainThreadAsync(); + Global.OutputPane.Clear(); + StateStorer.ClearState(); break; } } else { - UpdateChannelWindows(xCmd, xMsg); + await UpdateChannelWindowsAsync(xCmd, xMsg); } } } @@ -178,6 +178,19 @@ namespace Cosmos.VS.Windows return xWindow as ToolWindowPane2; } + public async Task FindWindowAsync(Type aWindowType) + { + // Get the instance number 0 of this tool window. + // Our windows are single instance so this instance will be the only one. + // The last flag is set to true so that if the tool window does not exists it will be created. + var xWindow = await FindToolWindowAsync(aWindowType, 0, true, default); + if (xWindow?.Frame == null) + { + throw new NotSupportedException("Failed to create the Cosmos tool window."); + } + return xWindow as ToolWindowPane2; + } + public ToolWindowPaneChannel FindChannelWindow(Type aWindowType) { // Get the instance number 0 of this tool window. @@ -191,31 +204,40 @@ namespace Cosmos.VS.Windows return xWindow as ToolWindowPaneChannel; } - public void UpdateChannelWindows(ushort aChannelAndCommand, byte[] aData) + public async Task FindChannelWindowAsync(Type aWindowType) { - System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, - (Action)delegate () - { - foreach (var xType in mAllChannelWindowTypes) - { - var xWindow = FindChannelWindow(xType); - xWindow.UserControl.Package = this; - xWindow.UserControl.HandleChannelMessage(aChannelAndCommand, aData); - } - } - ); + // Get the instance number 0 of this tool window. + // Our windows are single instance so this instance will be the only one. + // The last flag is set to true so that if the tool window does not exists it will be created. + var xWindow = await FindToolWindowAsync(aWindowType, 0, true, default); + if (xWindow?.Frame == null) + { + throw new NotSupportedException("Failed to create the Cosmos tool window."); + } + return xWindow as ToolWindowPaneChannel; } - public void UpdateWindow(Type aWindowType, string aTag, byte[] aData) + public async Task UpdateChannelWindowsAsync(ushort aChannelAndCommand, byte[] aData) { - System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, - (Action)delegate () - { - var xWindow = FindWindow(aWindowType); - xWindow.UserControl.Package = this; - xWindow.UserControl.Update(aTag, aData); - } - ); + await JoinableTaskFactory.SwitchToMainThreadAsync(); + + foreach (var xType in mAllChannelWindowTypes) + { + var xWindow = await FindChannelWindowAsync(xType); + + xWindow.UserControl.Package = this; + xWindow.UserControl.HandleChannelMessage(aChannelAndCommand, aData); + } + } + + private async Task UpdateWindowAsync(Type aWindowType, string aTag, byte[] aData) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(); + + var xWindow = await FindWindowAsync(aWindowType); + + xWindow.UserControl.Package = this; + xWindow.UserControl.Update(aTag, aData); } public void StoreAllStates()