diff --git a/Common/Product/SharedProject/TaskDialog.cs b/Common/Product/SharedProject/TaskDialog.cs deleted file mode 100644 index 602e96f95..000000000 --- a/Common/Product/SharedProject/TaskDialog.cs +++ /dev/null @@ -1,793 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools -{ - internal sealed class TaskDialog - { - private readonly IServiceProvider _provider; - private readonly List _buttons; - private readonly List _radioButtons; - - public TaskDialog(IServiceProvider provider) - { - this._provider = provider; - this._buttons = new List(); - this._radioButtons = new List(); - this.UseCommandLinks = true; - } - - public static TaskDialog ForException( - IServiceProvider provider, - Exception exception, - string message = null, - string issueTrackerUrl = null - ) - { - var suffix = string.IsNullOrEmpty(issueTrackerUrl) ? - "Please press Ctrl+C to copy the contents of this dialog and report this error." : - "Please press Ctrl+C to copy the contents of this dialog and report this error to our issue tracker."; - - if (string.IsNullOrEmpty(message)) - { - message = suffix; - } - else - { - message += Environment.NewLine + Environment.NewLine + suffix; - } - - var td = new TaskDialog(provider) - { - MainInstruction = "An unexpected error occurred", - Content = message, - EnableHyperlinks = true, - CollapsedControlText = "Show &details", - ExpandedControlText = "Hide &details", - ExpandedInformation = exception.ToString() - }; - td.Buttons.Add(TaskDialogButton.Close); - if (!string.IsNullOrEmpty(issueTrackerUrl)) - { - td.HyperlinkClicked += (s, e) => - { - if (e.Url == "issuetracker") - { - Process.Start(issueTrackerUrl); - } - }; - } - return td; - } - - public static void CallWithRetry( - Action action, - IServiceProvider provider, - string title, - string failedText, - string expandControlText, - string retryButtonText, - string cancelButtonText, - Func canRetry = null - ) - { - for (var retryCount = 1; ; ++retryCount) - { - try - { - action(retryCount); - return; - } - catch (Exception ex) - { - if (ex.IsCriticalException()) - { - throw; - } - if (canRetry != null && !canRetry(ex)) - { - throw; - } - - var td = new TaskDialog(provider) - { - Title = title, - MainInstruction = failedText, - Content = ex.Message, - CollapsedControlText = expandControlText, - ExpandedControlText = expandControlText, - ExpandedInformation = ex.ToString() - }; - var retry = new TaskDialogButton(retryButtonText); - td.Buttons.Add(retry); - td.Buttons.Add(new TaskDialogButton(cancelButtonText)); - var button = td.ShowModal(); - if (button != retry) - { - throw new OperationCanceledException(); - } - } - } - } - - public static T CallWithRetry( - Func func, - IServiceProvider provider, - string title, - string failedText, - string expandControlText, - string retryButtonText, - string cancelButtonText, - Func canRetry = null - ) - { - for (var retryCount = 1; ; ++retryCount) - { - try - { - return func(retryCount); - } - catch (Exception ex) - { - if (ex.IsCriticalException()) - { - throw; - } - if (canRetry != null && !canRetry(ex)) - { - throw; - } - - var td = new TaskDialog(provider) - { - Title = title, - MainInstruction = failedText, - Content = ex.Message, - CollapsedControlText = expandControlText, - ExpandedControlText = expandControlText, - ExpandedInformation = ex.ToString() - }; - var retry = new TaskDialogButton(retryButtonText); - var cancel = new TaskDialogButton(cancelButtonText); - td.Buttons.Add(retry); - td.Buttons.Add(cancel); - var button = td.ShowModal(); - if (button == cancel) - { - throw new OperationCanceledException(); - } - } - } - } - - public TaskDialogButton ShowModal() - { - var config = new NativeMethods.TASKDIALOGCONFIG(); - config.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.TASKDIALOGCONFIG)); - config.pButtons = IntPtr.Zero; - config.pRadioButtons = IntPtr.Zero; - - var uiShell = (IVsUIShell)this._provider.GetService(typeof(SVsUIShell)); - uiShell.GetDialogOwnerHwnd(out config.hwndParent); - uiShell.EnableModeless(0); - - var customButtons = new List(); - config.dwCommonButtons = 0; - - foreach (var button in this.Buttons) - { - var flag = GetButtonFlag(button); - if (flag != 0) - { - config.dwCommonButtons |= flag; - } - else - { - customButtons.Add(button); - } - } - - try - { - if (customButtons.Any()) - { - config.cButtons = (uint)customButtons.Count; - var ptr = config.pButtons = Marshal.AllocHGlobal(customButtons.Count * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON))); - for (var i = 0; i < customButtons.Count; ++i) - { - NativeMethods.TASKDIALOG_BUTTON data; - data.nButtonID = GetButtonId(null, null, i); - if (string.IsNullOrEmpty(customButtons[i].Subtext)) - { - data.pszButtonText = customButtons[i].Text; - } - else - { - data.pszButtonText = string.Format("{0}\n{1}", customButtons[i].Text, customButtons[i].Subtext); - } - Marshal.StructureToPtr(data, ptr + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), false); - } - } - else - { - config.cButtons = 0; - config.pButtons = IntPtr.Zero; - } - - if (this._buttons.Any() && this.SelectedButton != null) - { - config.nDefaultButton = GetButtonId(this.SelectedButton, customButtons); - } - else - { - config.nDefaultButton = 0; - } - - if (this._radioButtons.Any()) - { - config.cRadioButtons = (uint)this._radioButtons.Count; - var ptr = config.pRadioButtons = Marshal.AllocHGlobal(this._radioButtons.Count * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON))); - for (var i = 0; i < this._radioButtons.Count; ++i) - { - NativeMethods.TASKDIALOG_BUTTON data; - data.nButtonID = GetRadioId(null, null, i); - data.pszButtonText = this._radioButtons[i].Text; - Marshal.StructureToPtr(data, ptr + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), false); - } - - if (this.SelectedRadioButton != null) - { - config.nDefaultRadioButton = GetRadioId(this.SelectedRadioButton, this._radioButtons); - } - else - { - config.nDefaultRadioButton = 0; - } - } - - config.pszWindowTitle = this.Title; - config.pszMainInstruction = this.MainInstruction; - config.pszContent = this.Content; - config.pszExpandedInformation = this.ExpandedInformation; - config.pszExpandedControlText = this.ExpandedControlText; - config.pszCollapsedControlText = this.CollapsedControlText; - config.pszFooter = this.Footer; - config.pszVerificationText = this.VerificationText; - config.pfCallback = this.Callback; - config.hMainIcon = (IntPtr)GetIconResource(this.MainIcon); - config.hFooterIcon = (IntPtr)GetIconResource(this.FooterIcon); - - if (this.Width.HasValue) - { - config.cxWidth = (uint)this.Width.Value; - } - else - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_SIZE_TO_CONTENT; - } - if (this.EnableHyperlinks) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS; - } - if (this.AllowCancellation) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION; - } - if (this.UseCommandLinks && config.cButtons > 0) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS; - } - if (!this.ShowExpandedInformationInContent) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA; - } - if (this.ExpandedByDefault) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT; - } - if (this.SelectedVerified) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED; - } - if (this.CanMinimize) - { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED; - } - - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW; - - int selectedButton, selectedRadioButton; - bool verified; - ErrorHandler.ThrowOnFailure(NativeMethods.TaskDialogIndirect( - ref config, - out selectedButton, - out selectedRadioButton, - out verified - )); - - this.SelectedButton = GetButton(selectedButton, customButtons); - this.SelectedRadioButton = GetRadio(selectedRadioButton, this._radioButtons); - this.SelectedVerified = verified; - } - finally - { - uiShell.EnableModeless(1); - - if (config.pButtons != IntPtr.Zero) - { - for (var i = 0; i < customButtons.Count; ++i) - { - Marshal.DestroyStructure(config.pButtons + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), typeof(NativeMethods.TASKDIALOG_BUTTON)); - } - Marshal.FreeHGlobal(config.pButtons); - } - if (config.pRadioButtons != IntPtr.Zero) - { - for (var i = 0; i < this._radioButtons.Count; ++i) - { - Marshal.DestroyStructure(config.pRadioButtons + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), typeof(NativeMethods.TASKDIALOG_BUTTON)); - } - Marshal.FreeHGlobal(config.pRadioButtons); - } - } - - return this.SelectedButton; - } - - private int Callback(IntPtr hwnd, uint uNotification, UIntPtr wParam, IntPtr lParam, IntPtr lpRefData) - { - try - { - switch ((NativeMethods.TASKDIALOG_NOTIFICATION)uNotification) - { - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_CREATED: - foreach (var btn in this._buttons.Where(b => b.ElevationRequired)) - { - NativeMethods.SendMessage( - hwnd, - (int)NativeMethods.TASKDIALOG_MESSAGE.TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, - new IntPtr(GetButtonId(btn, this._buttons)), - new IntPtr(1) - ); - } - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_NAVIGATED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_BUTTON_CLICKED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_HYPERLINK_CLICKED: - var url = Marshal.PtrToStringUni(lParam); - var hevt = HyperlinkClicked; - if (hevt != null) - { - hevt(this, new TaskDialogHyperlinkClickedEventArgs(url)); - } - else - { - Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true }); - } - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_TIMER: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_DESTROYED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_RADIO_BUTTON_CLICKED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_DIALOG_CONSTRUCTED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_VERIFICATION_CLICKED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_HELP: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_EXPANDO_BUTTON_CLICKED: - break; - default: - break; - } - return VSConstants.S_OK; - } - catch (Exception ex) - { - if (ex.IsCriticalException()) - { - throw; - } - return Marshal.GetHRForException(ex); - } - } - - public string Title { get; set; } - public string MainInstruction { get; set; } - public string Content { get; set; } - public string VerificationText { get; set; } - public string ExpandedInformation { get; set; } - public string Footer { get; set; } - - public bool ExpandedByDefault { get; set; } - public bool ShowExpandedInformationInContent { get; set; } - public string ExpandedControlText { get; set; } - public string CollapsedControlText { get; set; } - - public int? Width { get; set; } - public bool EnableHyperlinks { get; set; } - public bool AllowCancellation { get; set; } - public bool UseCommandLinks { get; set; } - public bool CanMinimize { get; set; } - - public TaskDialogIcon MainIcon { get; set; } - public TaskDialogIcon FooterIcon { get; set; } - - /// - /// Raised when a hyperlink in the dialog is clicked. If no event - /// handlers are added, the default behavior is to open an external - /// browser. - /// - public event EventHandler HyperlinkClicked; - - public List Buttons => this._buttons; - - public List RadioButtons => this._radioButtons; - - public TaskDialogButton SelectedButton { get; set; } - public TaskDialogButton SelectedRadioButton { get; set; } - public bool SelectedVerified { get; set; } - - private static NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS GetButtonFlag(TaskDialogButton button) - { - if (button == TaskDialogButton.OK) - { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_OK_BUTTON; - } - else if (button == TaskDialogButton.Cancel) - { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CANCEL_BUTTON; - } - else if (button == TaskDialogButton.Yes) - { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_YES_BUTTON; - } - else if (button == TaskDialogButton.No) - { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_NO_BUTTON; - } - else if (button == TaskDialogButton.Retry) - { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_RETRY_BUTTON; - } - else if (button == TaskDialogButton.Close) - { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CLOSE_BUTTON; - } - else - { - return 0; - } - } - - private static NativeMethods.TASKDIALOG_ICON GetIconResource(TaskDialogIcon icon) - { - switch (icon) - { - case TaskDialogIcon.None: - return 0; - case TaskDialogIcon.Error: - return NativeMethods.TASKDIALOG_ICON.TD_ERROR_ICON; - case TaskDialogIcon.Warning: - return NativeMethods.TASKDIALOG_ICON.TD_WARNING_ICON; - case TaskDialogIcon.Information: - return NativeMethods.TASKDIALOG_ICON.TD_INFORMATION_ICON; - case TaskDialogIcon.Shield: - return NativeMethods.TASKDIALOG_ICON.TD_SHIELD_ICON; - default: - throw new ArgumentException("Invalid TaskDialogIcon value", "icon"); - } - } - - private static int GetButtonId( - TaskDialogButton button, - IList customButtons = null, - int indexHint = -1 - ) - { - if (indexHint >= 0) - { - return indexHint + 1000; - } - - if (button == TaskDialogButton.OK) - { - return NativeMethods.IDOK; - } - else if (button == TaskDialogButton.Cancel) - { - return NativeMethods.IDCANCEL; - } - else if (button == TaskDialogButton.Yes) - { - return NativeMethods.IDYES; - } - else if (button == TaskDialogButton.No) - { - return NativeMethods.IDNO; - } - else if (button == TaskDialogButton.Retry) - { - return NativeMethods.IDRETRY; - } - else if (button == TaskDialogButton.Close) - { - return NativeMethods.IDCLOSE; - } - else if (customButtons != null) - { - var i = customButtons.IndexOf(button); - if (i >= 0) - { - return i + 1000; - } - } - - return -1; - } - - private static TaskDialogButton GetButton(int id, IList customButtons = null) - { - switch (id) - { - case NativeMethods.IDOK: - return TaskDialogButton.OK; - case NativeMethods.IDCANCEL: - return TaskDialogButton.Cancel; - case NativeMethods.IDYES: - return TaskDialogButton.Yes; - case NativeMethods.IDNO: - return TaskDialogButton.No; - case NativeMethods.IDRETRY: - return TaskDialogButton.Retry; - case NativeMethods.IDCLOSE: - return TaskDialogButton.Close; - } - - if (customButtons != null && id >= 1000 && id - 1000 < customButtons.Count) - { - return customButtons[id - 1000]; - } - - return null; - } - - private static int GetRadioId( - TaskDialogButton button, - IList buttons, - int indexHint = -1 - ) - { - if (indexHint >= 0) - { - return indexHint + 2000; - } - - return buttons.IndexOf(button) + 2000; - } - - private static TaskDialogButton GetRadio(int id, IList buttons) - { - if (id >= 2000 && id - 2000 < buttons.Count) - { - return buttons[id - 2000]; - } - - return null; - } - - private static class NativeMethods - { - internal const int IDOK = 1; - internal const int IDCANCEL = 2; - internal const int IDABORT = 3; - internal const int IDRETRY = 4; - internal const int IDIGNORE = 5; - internal const int IDYES = 6; - internal const int IDNO = 7; - internal const int IDCLOSE = 8; - - internal enum TASKDIALOG_FLAGS - { - TDF_ENABLE_HYPERLINKS = 0x0001, - TDF_USE_HICON_MAIN = 0x0002, - TDF_USE_HICON_FOOTER = 0x0004, - TDF_ALLOW_DIALOG_CANCELLATION = 0x0008, - TDF_USE_COMMAND_LINKS = 0x0010, - TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020, - TDF_EXPAND_FOOTER_AREA = 0x0040, - TDF_EXPANDED_BY_DEFAULT = 0x0080, - TDF_VERIFICATION_FLAG_CHECKED = 0x0100, - TDF_SHOW_PROGRESS_BAR = 0x0200, - TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400, - TDF_CALLBACK_TIMER = 0x0800, - TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000, - TDF_RTL_LAYOUT = 0x2000, - TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000, - TDF_CAN_BE_MINIMIZED = 0x8000, - TDF_SIZE_TO_CONTENT = 0x01000000 - } - - internal enum TASKDIALOG_COMMON_BUTTON_FLAGS - { - TDCBF_OK_BUTTON = 0x0001, - TDCBF_YES_BUTTON = 0x0002, - TDCBF_NO_BUTTON = 0x0004, - TDCBF_CANCEL_BUTTON = 0x0008, - TDCBF_RETRY_BUTTON = 0x0010, - TDCBF_CLOSE_BUTTON = 0x0020 - } - - internal enum TASKDIALOG_NOTIFICATION : uint - { - TDN_CREATED = 0, - TDN_NAVIGATED = 1, - TDN_BUTTON_CLICKED = 2, // wParam = Button ID - TDN_HYPERLINK_CLICKED = 3, // lParam = (LPCWSTR)pszHREF - TDN_TIMER = 4, // wParam = Milliseconds since dialog created or timer reset - TDN_DESTROYED = 5, - TDN_RADIO_BUTTON_CLICKED = 6, // wParam = Radio Button ID - TDN_DIALOG_CONSTRUCTED = 7, - TDN_VERIFICATION_CLICKED = 8, // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0 - TDN_HELP = 9, - TDN_EXPANDO_BUTTON_CLICKED = 10 // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded) - }; - - internal enum TASKDIALOG_ICON : ushort - { - TD_WARNING_ICON = unchecked((ushort)-1), - TD_ERROR_ICON = unchecked((ushort)-2), - TD_INFORMATION_ICON = unchecked((ushort)-3), - TD_SHIELD_ICON = unchecked((ushort)-4) - } - - private const int WM_USER = 0x0400; - - internal enum TASKDIALOG_MESSAGE : int - { - TDM_NAVIGATE_PAGE = WM_USER + 101, - TDM_CLICK_BUTTON = WM_USER + 102, // wParam = Button ID - TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, // wParam = 0 (nonMarque) wParam != 0 (Marquee) - TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, // wParam = new progress state - TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, // lParam = MAKELPARAM(nMinRange, nMaxRange) - TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, // wParam = new position - TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints) - TDM_SET_ELEMENT_TEXT = WM_USER + 108, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) - TDM_CLICK_RADIO_BUTTON = WM_USER + 110, // wParam = Radio Button ID - TDM_ENABLE_BUTTON = WM_USER + 111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID - TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID - TDM_CLICK_VERIFICATION = WM_USER + 113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus) - TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) - TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required) - TDM_UPDATE_ICON = WM_USER + 116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) - } - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist", - Justification = "Entry point exists but CA can't find it")] - [DllImport("comctl32.dll", SetLastError = true)] - internal static extern int TaskDialogIndirect( - ref TASKDIALOGCONFIG pTaskConfig, - out int pnButton, - out int pnRadioButton, - [MarshalAs(UnmanagedType.Bool)] out bool pfverificationFlagChecked); - - internal delegate int PFTASKDIALOGCALLBACK(IntPtr hwnd, uint uNotification, UIntPtr wParam, IntPtr lParam, IntPtr lpRefData); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct TASKDIALOG_BUTTON - { - public int nButtonID; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszButtonText; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct TASKDIALOGCONFIG - { - public uint cbSize; - public IntPtr hwndParent; - public IntPtr hInstance; - public TASKDIALOG_FLAGS dwFlags; - public TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszWindowTitle; - public IntPtr hMainIcon; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszMainInstruction; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszContent; - public uint cButtons; - public IntPtr pButtons; - public int nDefaultButton; - public uint cRadioButtons; - public IntPtr pRadioButtons; - public int nDefaultRadioButton; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszVerificationText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszExpandedInformation; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszExpandedControlText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszCollapsedControlText; - public IntPtr hFooterIcon; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszFooter; - public PFTASKDIALOGCALLBACK pfCallback; - public IntPtr lpCallbackData; - public uint cxWidth; - } - - [DllImport("user32.dll")] - internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); - } - } - - internal class TaskDialogButton - { - public TaskDialogButton(string text) - { - var i = text.IndexOfAny(Environment.NewLine.ToCharArray()); - if (i < 0) - { - this.Text = text; - } - else - { - this.Text = text.Remove(i); - this.Subtext = text.Substring(i).TrimStart(); - } - } - - public TaskDialogButton(string text, string subtext) - { - this.Text = text; - this.Subtext = subtext; - } - - public string Text { get; set; } - public string Subtext { get; set; } - public bool ElevationRequired { get; set; } - - private TaskDialogButton() { } - public static readonly TaskDialogButton OK = new TaskDialogButton(); - public static readonly TaskDialogButton Cancel = new TaskDialogButton(); - public static readonly TaskDialogButton Yes = new TaskDialogButton(); - public static readonly TaskDialogButton No = new TaskDialogButton(); - public static readonly TaskDialogButton Retry = new TaskDialogButton(); - public static readonly TaskDialogButton Close = new TaskDialogButton(); - } - - internal sealed class TaskDialogHyperlinkClickedEventArgs : EventArgs - { - private readonly string _url; - - public TaskDialogHyperlinkClickedEventArgs(string url) - { - this._url = url; - } - - public string Url => this._url; - } - - internal enum TaskDialogIcon - { - None, - Error, - Warning, - Information, - Shield - } -} diff --git a/Nodejs/Product/Nodejs/Nodejs.csproj b/Nodejs/Product/Nodejs/Nodejs.csproj index 0637b3061..81b4ff7fa 100644 --- a/Nodejs/Product/Nodejs/Nodejs.csproj +++ b/Nodejs/Product/Nodejs/Nodejs.csproj @@ -245,9 +245,6 @@ SharedProject\SolutionEventsListener.cs - - SharedProject\TaskDialog.cs - Project\TypeScriptHelpers.cs diff --git a/Nodejs/Product/Nodejs/Project/NodejsFolderNode.cs b/Nodejs/Product/Nodejs/Project/NodejsFolderNode.cs index 6981a2996..4f8915a13 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsFolderNode.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsFolderNode.cs @@ -1,7 +1,11 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; +using System.Diagnostics; using System.IO; using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudioTools; using Microsoft.VisualStudioTools.Project; @@ -29,37 +33,13 @@ internal override int IncludeInProject(bool includeChildren) // http://nodejstools.codeplex.com/workitem/1432 // Check if the folder is node_modules, and warn the user to ensure they don't run into this issue or at least set expectations appropriately. var nodeModulesPath = Path.Combine(this._project.FullPathToChildren, "node_modules"); - if (CommonUtils.IsSameDirectory(nodeModulesPath, this.ItemNode.Url) && - !ShouldIncludeNodeModulesFolderInProject()) + if (CommonUtils.IsSameDirectory(nodeModulesPath, this.ItemNode.Url)) { + Utilities.ShowMessageBox( + this._project.Site, Resources.IncludeNodeModulesContent, SR.ProductName, OLEMSGICON.OLEMSGICON_WARNING, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); return VSConstants.S_OK; } return base.IncludeInProject(includeChildren); } - - private bool ShouldIncludeNodeModulesFolderInProject() - { - var includeNodeModulesButton = new TaskDialogButton(Resources.IncludeNodeModulesIncludeTitle, Resources.IncludeNodeModulesIncludeDescription); - var cancelOperationButton = new TaskDialogButton(Resources.IncludeNodeModulesCancelTitle); - var taskDialog = new TaskDialog(this._project.ProjectMgr.Site) - { - AllowCancellation = true, - EnableHyperlinks = true, - Title = SR.ProductName, - MainIcon = TaskDialogIcon.Warning, - Content = Resources.IncludeNodeModulesContent, - Buttons = { - cancelOperationButton, - includeNodeModulesButton - }, - FooterIcon = TaskDialogIcon.Information, - Footer = Resources.IncludeNodeModulesInformation, - SelectedButton = cancelOperationButton - }; - - var button = taskDialog.ShowModal(); - - return button == includeNodeModulesButton; - } } } diff --git a/Nodejs/Product/Nodejs/Project/NodejsProjectNode.cs b/Nodejs/Product/Nodejs/Project/NodejsProjectNode.cs index 1bdbb9df5..0472705ac 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsProjectNode.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsProjectNode.cs @@ -2,12 +2,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -21,7 +19,6 @@ using Microsoft.VisualStudioTools; using Microsoft.VisualStudioTools.Project; using Microsoft.VisualStudioTools.Project.Automation; -using MSBuild = Microsoft.Build.Evaluation; using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; namespace Microsoft.NodejsTools.Project @@ -76,7 +73,7 @@ private void NodeModules_FinishedRefresh(object sender, EventArgs e) } } - private static string[] _excludedAvailableItems = new[] { + private readonly static string[] _excludedAvailableItems = new[] { "ApplicationDefinition", "Page", "Resource", @@ -586,72 +583,14 @@ public async Task CheckForLongPaths(string npmArguments = null) try { this._isCheckingForLongPaths = true; - TaskDialogButton dedupeButton, ignoreButton, disableButton; - var taskDialog = new TaskDialog(NodejsPackage.Instance) - { - AllowCancellation = true, - EnableHyperlinks = true, - Title = Resources.LongPathWarningTitle, - MainIcon = TaskDialogIcon.Warning, - Content = Resources.LongPathWarningText, - CollapsedControlText = Resources.LongPathShowPathsExceedingTheLimit, - ExpandedControlText = Resources.LongPathHidePathsExceedingTheLimit, - Buttons = { - (dedupeButton = new TaskDialogButton(Resources.LongPathNpmDedupe, Resources.LongPathNpmDedupeDetail)), - (ignoreButton = new TaskDialogButton(Resources.LongPathDoNothingButWarnNextTime)), - (disableButton = new TaskDialogButton(Resources.LongPathDoNothingAndDoNotWarnAgain, Resources.LongPathDoNothingAndDoNotWarnAgainDetail)) - }, - FooterIcon = TaskDialogIcon.Information, - Footer = Resources.LongPathFooter - }; - - taskDialog.HyperlinkClicked += (sender, e) => - { - switch (e.Url) - { - case "#msdn": - Process.Start("https://go.microsoft.com/fwlink/?LinkId=454508"); - break; - case "#uservoice": - Process.Start("https://go.microsoft.com/fwlink/?LinkID=456509"); - break; - case "#help": - Process.Start("https://go.microsoft.com/fwlink/?LinkId=456511"); - break; - default: - System.Windows.Clipboard.SetText(e.Url); - break; - } - }; - - recheck: var longPaths = await Task.Factory.StartNew(() => - GetLongSubPaths(this.ProjectHome) - .Concat(GetLongSubPaths(this._intermediateOutputPath)) - .Select(lpi => string.Format(CultureInfo.InvariantCulture, "\u2022 {1}\u00A0{2}", lpi.FullPath, lpi.RelativePath, Resources.LongPathClickToCopy)) - .ToArray()); - if (longPaths.Length == 0) - { - return; - } - taskDialog.ExpandedInformation = string.Join("\r\n", longPaths); + GetLongSubPaths(this.ProjectHome).Any() || GetLongSubPaths(this._intermediateOutputPath).Any()); - var button = taskDialog.ShowModal(); - if (button == dedupeButton) - { - var repl = NodejsPackage.Instance.OpenReplWindow(focus: false); - await repl.ExecuteCommand(".npm dedupe").HandleAllExceptions(SR.ProductName); - - taskDialog.Content += "\r\n\r\n" + Resources.LongPathNpmDedupeDidNotHelp; - taskDialog.Buttons.Remove(dedupeButton); - goto recheck; - } - else if (button == disableButton) + if (longPaths) { - var page = NodejsPackage.Instance.GeneralOptionsPage; - page.CheckForLongPaths = false; - page.SaveSettingsToStorage(); + Utilities.ShowMessageBox( + this.Site, Resources.LongPathWarningText, SR.ProductName, OLEMSGICON.OLEMSGICON_WARNING, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } finally diff --git a/Nodejs/Product/Nodejs/SharedProject/ProjectNode.CopyPaste.cs b/Nodejs/Product/Nodejs/SharedProject/ProjectNode.CopyPaste.cs index 100cf438c..59c722753 100644 --- a/Nodejs/Product/Nodejs/SharedProject/ProjectNode.CopyPaste.cs +++ b/Nodejs/Product/Nodejs/SharedProject/ProjectNode.CopyPaste.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections; @@ -1113,7 +1113,6 @@ private Addition CanAddFileFromProjectReference(string projectRef, string target { throw; } - TaskDialog.ForException(this.Project.Site, e, string.Empty, this.Project.IssueTrackerUrl).ShowModal(); return null; } } diff --git a/Nodejs/Product/ProjectWizard/CloudServiceWizard.cs b/Nodejs/Product/ProjectWizard/CloudServiceWizard.cs index f49cecab5..a62723794 100644 --- a/Nodejs/Product/ProjectWizard/CloudServiceWizard.cs +++ b/Nodejs/Product/ProjectWizard/CloudServiceWizard.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; @@ -8,6 +8,8 @@ using System.Reflection; using Microsoft.NodejsTools.Project; using Microsoft.VisualStudio.Settings; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TemplateWizard; using Microsoft.VisualStudioTools; using ProjectItem = EnvDTE.ProjectItem; @@ -17,8 +19,6 @@ namespace Microsoft.NodejsTools.ProjectWizard public sealed class CloudServiceWizard : IWizard { private IWizard _wizard; - private readonly bool _recommendUpgrade; - private const string AzureToolsDownload = "https://go.microsoft.com/fwlink/?LinkId=746956"; /// /// The settings collection where "Suppress{dialog}" settings are stored @@ -26,22 +26,6 @@ public sealed class CloudServiceWizard : IWizard private const string DontShowUpgradeDialogAgainCollection = "NodejsTools\\Dialogs"; private const string DontShowUpgradeDialogAgainProperty = "SuppressUpgradeAzureTools"; - private static bool ShouldRecommendUpgrade(Assembly asm) - { - var attr = asm.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false) - .OfType() - .FirstOrDefault(); - - Version ver; - if (attr != null && Version.TryParse(attr.Version, out ver)) - { - Debug.WriteLine(ver); - // 2.4 is the minimun requirement. - return ver < new Version(2, 4); - } - return false; - } - public CloudServiceWizard() { try @@ -50,8 +34,6 @@ public CloudServiceWizard() // the WebPI download. var asm = Assembly.Load("Microsoft.VisualStudio.CloudService.Wizard,Version=1.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"); - _recommendUpgrade = ShouldRecommendUpgrade(asm); - var type = asm.GetType("Microsoft.VisualStudio.CloudService.Wizard.CloudServiceWizard"); _wizard = type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[0]) as IWizard; } @@ -126,84 +108,14 @@ public void RunStarted(object automationObject, Dictionary repla // If it fails (doesn't exist/contains files/read-only), let the directory stay. } - var dlg = new TaskDialog(provider) - { - Title = SR.ProductName, - MainInstruction = ProjectWizardResources.AzureToolsRequired, - Content = ProjectWizardResources.AzureToolsInstallInstructions, - AllowCancellation = true - }; - var download = new TaskDialogButton(ProjectWizardResources.DownloadAndInstall); - dlg.Buttons.Add(download); - dlg.Buttons.Add(TaskDialogButton.Cancel); - - if (dlg.ShowModal() == download) - { - Process.Start(new ProcessStartInfo(AzureToolsDownload)); - throw new WizardCancelledException(); - } + var uiShell = ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; + Debug.Assert(uiShell != null, "uiShell was null."); + uiShell.ShowMessageBox(0, Guid.Empty, SR.ProductName, ProjectWizardResources.AzureToolsRequired, null, 0, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_CRITICAL, 1, out var result); // User cancelled, so go back to the New Project dialog throw new WizardBackoutException(); } - if (_recommendUpgrade) - { - var sm = SettingsManagerCreator.GetSettingsManager(provider); - var store = sm.GetReadOnlySettingsStore(SettingsScope.UserSettings); - - if (!store.CollectionExists(DontShowUpgradeDialogAgainCollection) || - !store.GetBoolean(DontShowUpgradeDialogAgainCollection, DontShowUpgradeDialogAgainProperty, false)) - { - var dlg = new TaskDialog(provider) - { - Title = SR.ProductName, - MainInstruction = ProjectWizardResources.AzureToolsUpgradeRecommended, - Content = ProjectWizardResources.AzureToolsUpgradeInstructions, - AllowCancellation = true, - VerificationText = ProjectWizardResources.DontShowAgain - }; - var download = new TaskDialogButton(ProjectWizardResources.DownloadAndInstall); - dlg.Buttons.Add(download); - var cont = new TaskDialogButton(ProjectWizardResources.ContinueWithoutAzureToolsUpgrade); - dlg.Buttons.Add(cont); - dlg.Buttons.Add(TaskDialogButton.Cancel); - - var response = dlg.ShowModal(); - - if (response != cont) - { - try - { - Directory.Delete(replacementsDictionary["$destinationdirectory$"]); - Directory.Delete(replacementsDictionary["$solutiondirectory$"]); - } - catch - { - // If it fails (doesn't exist/contains files/read-only), let the directory stay. - } - } - - if (dlg.SelectedVerified) - { - var rwStore = sm.GetWritableSettingsStore(SettingsScope.UserSettings); - rwStore.CreateCollection(DontShowUpgradeDialogAgainCollection); - rwStore.SetBoolean(DontShowUpgradeDialogAgainCollection, DontShowUpgradeDialogAgainProperty, true); - } - - if (response == download) - { - Process.Start(new ProcessStartInfo(AzureToolsDownload)); - throw new WizardCancelledException(); - } - else if (response == TaskDialogButton.Cancel) - { - // User cancelled, so go back to the New Project dialog - throw new WizardBackoutException(); - } - } - } - // Run the original wizard to get the right replacements _wizard.RunStarted(automationObject, replacementsDictionary, runKind, customParams); } diff --git a/Nodejs/Product/ProjectWizard/ProjectWizard.csproj b/Nodejs/Product/ProjectWizard/ProjectWizard.csproj index 20f871828..19e1bcbe2 100644 --- a/Nodejs/Product/ProjectWizard/ProjectWizard.csproj +++ b/Nodejs/Product/ProjectWizard/ProjectWizard.csproj @@ -63,9 +63,6 @@ ExceptionExtensions.cs - - TaskDialog.cs - Guids.cs