diff --git a/Vsix/CodeConversion.cs b/Vsix/CodeConversion.cs index ae0f26840..0a102a5df 100644 --- a/Vsix/CodeConversion.cs +++ b/Vsix/CodeConversion.cs @@ -25,7 +25,6 @@ internal class CodeConversion private readonly IAsyncServiceProvider _serviceProvider; private readonly JoinableTaskFactory _joinableTaskFactory; private readonly VisualStudioWorkspace _visualStudioWorkspace; - public static readonly string ConverterTitle = "Code converter"; private static readonly string Intro = Environment.NewLine + Environment.NewLine + new string(Enumerable.Repeat('-', 80).ToArray()) + Environment.NewLine; private readonly OutputWindow _outputWindow; private readonly Cancellation _packageCancellation; diff --git a/Vsix/CodeConverterPackage.cs b/Vsix/CodeConverterPackage.cs index 9dc1d45cb..e6864f864 100644 --- a/Vsix/CodeConverterPackage.cs +++ b/Vsix/CodeConverterPackage.cs @@ -84,58 +84,17 @@ public sealed class CodeConverterPackage : AsyncPackage internal Cancellation PackageCancellation { get; } = new Cancellation(); - private readonly AssemblyName _thisAssemblyName; - private readonly HashSet _ourAssemblyNames; /// /// Initializes a new instance of package class. /// public CodeConverterPackage() { - var thisAssembly = GetType().Assembly; - _thisAssemblyName = thisAssembly.GetName(); - _ourAssemblyNames = new HashSet(new[] { _thisAssemblyName }.Concat(thisAssembly.GetReferencedAssemblies().Where(a => a.Name.StartsWith("ICSharpCode"))).Select(a => a.FullName)); // Inside this method you can place any initialization code that does not require // any Visual Studio service because at this point the package object is created but // not sited yet inside Visual Studio environment. The place to do all the other // initialization is the Initialize method. } - // System.Threading.Tasks.Dataflow 4.5.24.0 shipped with VS2017 15.9.21+28307.1064 but we want to target 4.6.0.0 - private Assembly LoadWithoutVersionForOurDependencies(object sender, ResolveEventArgs args) - { - var requestedAssemblyName = new AssemblyName(args.Name); - if (requestedAssemblyName.Version != null && IsThisExtensionRequestingAssembly()) { - return LoadAnyVersionOfAssembly(requestedAssemblyName); - } - return null; - - } - - private static Assembly LoadAnyVersionOfAssembly(AssemblyName assemblyName) - { - try { - return Assembly.Load(new AssemblyName(assemblyName.Name){CultureName = assemblyName.CultureName}); - } catch (FileNotFoundException e) when (e.FileName.Contains("Microsoft.VisualStudio.LanguageServices") && ProbablyRequiresVsUpgrade) { - MessageBox.Show( - "Code Converter cannot find `Microsoft.VisualStudio.LanguageServices`. Please upgrade Visual Studio to version 15.9.3 or above.\r\n\r\n" + - "If after upgrading you still see this error, attach your activity log %AppData%\\Microsoft\\VisualStudio\\\\ActivityLog.xml to a GitHub issue at https://github.com/icsharpcode/CodeConverter \r\n\r\n" + - "You can press Ctrl + C to copy this message", - "Upgrade Visual Studio", MessageBoxButton.OK); - return null; - } - } - - private bool IsThisExtensionRequestingAssembly() - { - return GetPossibleRequestingAssemblies().Any(requesting => _ourAssemblyNames.Contains(requesting.FullName)); - } - - private IEnumerable GetPossibleRequestingAssemblies() - { - return new StackTrace().GetFrames().Select(f => f.GetMethod().DeclaringType?.Assembly) - .Select(a => a.GetName()).SkipWhile(a => Equals(a, _thisAssemblyName)); - } - /// /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. @@ -155,25 +114,6 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke await base.InitializeAsync(cancellationToken, progress); } - public static bool ProbablyRequiresVsUpgrade { - get { - var version = FullVsVersion; - return version == null || version < new Version(15, 9, 3, 0); - } - } - - private static Version FullVsVersion { - get { - string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "msenv.dll"); - - if (File.Exists(path)) { - var fvi = FileVersionInfo.GetVersionInfo(path); - return new Version(fvi.ProductMajorPart, fvi.ProductMinorPart, fvi.ProductBuildPart, - fvi.ProductPrivatePart); - } else return null; - } - } - internal OleMenuCommandWithBlockingStatus CreateCommand(Func callbackAsync, CommandID menuCommandId) { return new OleMenuCommandWithBlockingStatus(JoinableTaskFactory, PackageCancellation, callbackAsync, menuCommandId); diff --git a/Vsix/ConvertCSToVBCommand.cs b/Vsix/ConvertCSToVBCommand.cs index c4c91fb56..1941e74d4 100644 --- a/Vsix/ConvertCSToVBCommand.cs +++ b/Vsix/ConvertCSToVBCommand.cs @@ -167,7 +167,7 @@ private async Task SolutionOrProjectMenuItemCallbackAsync(CancellationToken canc var projects = VisualStudioInteraction.GetSelectedProjectsAsync(ProjectExtension); await _codeConversion.ConvertProjectsAsync(await projects, cancellationToken); } catch (Exception ex) { - await VisualStudioInteraction.ShowExceptionAsync(ServiceProvider, CodeConversion.ConverterTitle, ex); + await VisualStudioInteraction.ShowExceptionAsync(ex); } } @@ -179,7 +179,7 @@ private async Task ConvertDocumentAsync(string documentPath, Span selected, Canc try { await _codeConversion.ConvertDocumentAsync(documentPath, selected, cancellationToken); } catch (Exception ex) { - await VisualStudioInteraction.ShowExceptionAsync(ServiceProvider, CodeConversion.ConverterTitle, ex); + await VisualStudioInteraction.ShowExceptionAsync(ex); } } } diff --git a/Vsix/ConvertVBToCSCommand.cs b/Vsix/ConvertVBToCSCommand.cs index f2fa042c6..b73cdaf31 100644 --- a/Vsix/ConvertVBToCSCommand.cs +++ b/Vsix/ConvertVBToCSCommand.cs @@ -167,7 +167,7 @@ private async Task SolutionOrProjectMenuItemCallbackAsync(CancellationToken canc var projects = VisualStudioInteraction.GetSelectedProjectsAsync(ProjectExtension); await _codeConversion.ConvertProjectsAsync(await projects, cancellationToken); } catch (Exception ex) { - await VisualStudioInteraction.ShowExceptionAsync(ServiceProvider, CodeConversion.ConverterTitle, ex); + await VisualStudioInteraction.ShowExceptionAsync(ex); } } @@ -179,7 +179,7 @@ private async Task ConvertDocumentAsync(string documentPath, Span selected, Canc try { await _codeConversion.ConvertDocumentAsync(documentPath, selected, cancellationToken); } catch (Exception ex) { - await VisualStudioInteraction.ShowExceptionAsync(ServiceProvider, CodeConversion.ConverterTitle, ex); + await VisualStudioInteraction.ShowExceptionAsync(ex); } } } diff --git a/Vsix/VisualStudioInteraction.cs b/Vsix/VisualStudioInteraction.cs index 24020e87b..1190eabab 100644 --- a/Vsix/VisualStudioInteraction.cs +++ b/Vsix/VisualStudioInteraction.cs @@ -1,13 +1,16 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; using EnvDTE; using EnvDTE80; +using ICSharpCode.CodeConverter.Shared; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Shell; @@ -35,6 +38,24 @@ internal static class VisualStudioInteraction internal static DTE2 Dte => m_Dte ?? (m_Dte = Package.GetGlobalService(typeof(DTE)) as DTE2); private static CancellationToken CancelAllToken; + private static readonly Version m_LowestSupportedVersion = new Version(15, 7, 0, 0); + private static readonly Version m_FullVsVersion = GetFullVsVersion(); + private static readonly string m_Title = "Code converter " + new AssemblyName(typeof(CodeConversion).Assembly.FullName).Version.ToString(3) + " - Visual Studio " + m_FullVsVersion; + + private static Version GetFullVsVersion() + { + string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "msenv.dll"); + + if (File.Exists(path)) { + var fvi = FileVersionInfo.GetVersionInfo(path); + return new Version(fvi.ProductMajorPart, fvi.ProductMinorPart, fvi.ProductBuildPart, + fvi.ProductPrivatePart); + } else { + return null; + } + } + + internal static void Initialize(Cancellation packageCancellation) { CancelAllToken = packageCancellation.CancelAll; @@ -86,12 +107,19 @@ public static async Task GetTextDocumentAsync(this IWpfTextViewHo return textDocument; } - public static async Task ShowExceptionAsync(IAsyncServiceProvider serviceProvider, string title, Exception ex) + public static async Task ShowExceptionAsync(Exception ex) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken); if (!CancelAllToken.IsCancellationRequested) { - MessageBox.Show($"An error has occured during conversion - press Ctrl+C to copy the details: {ex}", - title, MessageBoxButton.OK, MessageBoxImage.Error); + var versionMessageSuffix = ""; + if (m_FullVsVersion < m_LowestSupportedVersion) { + versionMessageSuffix = $"{Environment.NewLine}This extension only supports VS {m_LowestSupportedVersion}+, you are currently using {m_FullVsVersion}"; + } + if (m_FullVsVersion.Major < 16) { + versionMessageSuffix = $"{Environment.NewLine}Support for VS2017 (15.*) is likely to end this year. You're using: {m_FullVsVersion}"; + } + MessageBox.Show($"An error has occured during conversion - press Ctrl+C to copy the details: {ex}{versionMessageSuffix}", + m_Title, MessageBoxButton.OK, MessageBoxImage.Error); } }