using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using PortingAssistantVSExtensionClient.Common; using PortingAssistantVSExtensionClient.Dialogs; using PortingAssistantVSExtensionClient.Models; using PortingAssistantVSExtensionClient.Options; using PortingAssistantVSExtensionClient.Utils; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.IO; using System.IO.Pipes; using Task = System.Threading.Tasks.Task; namespace PortingAssistantVSExtensionClient.Commands { /// /// Command handler /// internal sealed class SolutionAssessmentCommand { /// /// Command ID. /// public const int CommandId = PackageIds.SolutionAssessmentCommandId; /// /// Command menu group (command set GUID). /// public static readonly Guid CommandSet = new Guid(PackageGuids.guidPortingAssistantVSExtensionClientPackageCmdSetString); /// /// VS Package that provides this command, not null. /// private readonly AsyncPackage package; /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. /// Command service to add command to, not null. private SolutionAssessmentCommand(AsyncPackage package, OleMenuCommandService commandService) { this.package = package ?? throw new ArgumentNullException(nameof(package)); commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); var menuCommandID = new CommandID(CommandSet, CommandId); var menuItem = new MenuCommand(this.Execute, menuCommandID); commandService.AddCommand(menuItem); } /// /// Gets the instance of the command. /// public static SolutionAssessmentCommand Instance { get; private set; } private string SolutionName = ""; /// /// Gets the service provider from the owner package. /// private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider { get { return this.package; } } /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(AsyncPackage package) { // Switch to the main thread - the call to AddCommand in SolutionAssessmentCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; Instance = new SolutionAssessmentCommand(package, commandService); } /// /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// /// Event sender. /// Event args. private async void Execute(object sender, EventArgs e) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); try { var solutionFile = await CommandsCommon.GetSolutionPathAsync(); #if Dev16 VS19LSPTrigger(solutionFile) ; #endif if (!await CommandsCommon.CheckLanguageServerStatusAsync()) { NotificationUtils.ShowInfoMessageBox(PAGlobalService.Instance.Package, "Porting Assistant cannot be activated. Please open any .cs/.vb file if its not already opened.", "Porting Assistant can not be activated."); return; } if (!CommandsCommon.SetupPage()) return; // Verify Target framework selection before disabling all commands. if (UserSettings.Instance.TargetFramework.Equals(TargetFrameworkType.NO_SELECTION)) { if (!SelectTargetDialog.EnsureExecute()) return; } CommandsCommon.EnableAllCommand(false); SolutionName = Path.GetFileName(solutionFile); string pipeName = Guid.NewGuid().ToString(); // It's intended that we don't await for RunAssessmentAsync function for too long. CommandsCommon.RunAssessmentAsync(solutionFile, pipeName); PipeUtils.StartListenerConnection(pipeName, GetAssessmentCompletionTasks(this.package, SolutionName)); } catch (Exception ex) { NotificationUtils.ShowErrorMessageBox(this.package, $"Assessment failed for {SolutionName} due to {ex.Message}", "Assessment failed"); CommandsCommon.EnableAllCommand(true); } } public Func GetAssessmentCompletionTasks(AsyncPackage package, string solutionName) { async Task CompletionTask() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); try { if (!UserSettings.Instance.EnabledContinuousAssessment) { UserSettings.Instance.EnabledContinuousAssessment = true; UserSettings.Instance.UpdateContinuousAssessment(); await PortingAssistantLanguageClient.UpdateUserSettingsAsync(); } await NotificationUtils.UseStatusBarProgressAsync(2, 2, "Assessment successful"); await NotificationUtils.ShowInfoBarAsync( this.package, "Assessment successful. You can view the assessment results in the error list or view the green highlights in your source code."); UserSettings.Instance.SolutionAssessed = true; } catch (Exception ex) { NotificationUtils.ShowErrorMessageBox( package, $"Assessment failed for {solutionName} due to {ex.Message}", "Assessment failed"); } finally { CommandsCommon.EnableAllCommand(true); } } return CompletionTask; } private async void VS19LSPTrigger(string solutionFile) { try { var openFile = Path.Combine(Path.GetDirectoryName(solutionFile), "pa.ini"); if (!File.Exists(openFile)) { using (File.Create(openFile)) ; } var dte = await PAGlobalService.Instance.GetDTEServiceAsync(); dte.ItemOperations.OpenFile(openFile); await CommandsCommon.CheckLanguageServerStatusAsync(); } catch (Exception ex) { NotificationUtils.ShowErrorMessageBox(package, $"failed to load porting assistant in visual studio 2019 due to {ex.Message}", "failed to load porting assistant"); } } } }