From 9a1d3df3ebb774befcf4de15fa343eb720d4d4c8 Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 16:37:55 +0000 Subject: [PATCH 1/8] Modernize VSIX project: Convert to SDK style and add extensibility SDK support --- Vsix/Extension.cs | 12 +++ Vsix/VisualStudioInteraction.cs | 9 ++- Vsix/Vsix.csproj | 137 ++++++-------------------------- 3 files changed, 42 insertions(+), 116 deletions(-) create mode 100644 Vsix/Extension.cs diff --git a/Vsix/Extension.cs b/Vsix/Extension.cs new file mode 100644 index 000000000..5694252d9 --- /dev/null +++ b/Vsix/Extension.cs @@ -0,0 +1,12 @@ +using Microsoft.VisualStudio.Extensibility; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[VisualStudioContribution] +public class CodeConverterExtension : Extension +{ + public override ExtensionConfiguration ExtensionConfiguration => new() { + RequiresInProcessHosting = true, + Metadata = null + }; +} diff --git a/Vsix/VisualStudioInteraction.cs b/Vsix/VisualStudioInteraction.cs index a1e498658..4ac8a8187 100644 --- a/Vsix/VisualStudioInteraction.cs +++ b/Vsix/VisualStudioInteraction.cs @@ -32,8 +32,13 @@ internal static class VisualStudioInteraction { private static DTE2 _dte; - /// All calls and usages must be from the main thread> - internal static DTE2 Dte => _dte ??= Package.GetGlobalService(typeof(DTE)) as DTE2; + /// All calls and usages must be from the main thread + internal static DTE2 Dte { + get { + ThreadHelper.ThrowIfNotOnUIThread(); + return _dte ??= Package.GetGlobalService(typeof(DTE)) as DTE2; + } + } private static CancellationToken _cancelAllToken; private static readonly Version LowestSupportedVersion = new(16, 10, 0, 0); diff --git a/Vsix/Vsix.csproj b/Vsix/Vsix.csproj index 93d31a7af..7645b6add 100644 --- a/Vsix/Vsix.csproj +++ b/Vsix/Vsix.csproj @@ -1,145 +1,54 @@ - - + - 16.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - Debug - AnyCPU - 2.0 - ICSharpCode.CodeConverter.VsExtension - ICSharpCode.CodeConverter.VsExtension - {99498EF8-C9E0-433B-8D7B-EA8E9E66F0C7} - {82B43B9B-A64C-4715-B499-D71E9CA2BD60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - v4.7.2 + net472 + disable + disable + 12 + true + + true true - true - true true true - Roslyn - Program - $(DevEnvDir)devenv.exe - /rootsuffix $(VSSDKTargetPlatformRegRootSuffix) - false - False - win - 12.0 - - - - true - true - true - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - $(LocalAppData)\Microsoft\VisualStudio\15.0_8bd9890a\Extensions\frc3cnfo.23z - True - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + - - 1.8.4 - - - 10.0.2 - - + + + - - compile; build; native; contentfiles; analyzers; buildtransitive - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + + + + + Menus.ctmenu - Designer - true PreserveNewest + true - true PreserveNewest + true Always true - - - - - - - - - - - Component - - - - - - - - - - - - - - - + true VSPackage - Designer - - - {7ea075c6-6406-445c-ab77-6c47aff88d58} - CodeConverter - - + - - - - - - - - - - - \ No newline at end of file From 88fcf266e187b29d3b5d1592e05d2bcc402e8e30 Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 16:55:18 +0000 Subject: [PATCH 2/8] Phase 2: Migrate CodeConverterPackage to include Extension contribution --- Vsix/CodeConverterPackage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Vsix/CodeConverterPackage.cs b/Vsix/CodeConverterPackage.cs index e23f42539..623878a81 100644 --- a/Vsix/CodeConverterPackage.cs +++ b/Vsix/CodeConverterPackage.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.ComponentModelHost; +using Microsoft.VisualStudio.Extensibility; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Threading; From 3f26986a4619ce27824556c411796d64c779c9cb Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 17:38:19 +0000 Subject: [PATCH 3/8] Phase 2: Add initial Extensibility SDK command contributions --- Vsix/ConvertCSToVBExtensibilityCommand.cs | 25 +++++++++++++++++++++++ Vsix/ConvertVBToCSExtensibilityCommand.cs | 25 +++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 Vsix/ConvertCSToVBExtensibilityCommand.cs create mode 100644 Vsix/ConvertVBToCSExtensibilityCommand.cs diff --git a/Vsix/ConvertCSToVBExtensibilityCommand.cs b/Vsix/ConvertCSToVBExtensibilityCommand.cs new file mode 100644 index 000000000..b8ebae3ee --- /dev/null +++ b/Vsix/ConvertCSToVBExtensibilityCommand.cs @@ -0,0 +1,25 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Commands; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[VisualStudioContribution] +public class ConvertCSToVBExtensibilityCommand : Command +{ + private readonly CodeConverterPackage _package; + + public ConvertCSToVBExtensibilityCommand(CodeConverterPackage package) + { + _package = package; + } + + public override CommandConfiguration CommandConfiguration => new("%a3378a21-e939-40c9-9e4b-eb0cec7b7854%"); + + public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) + { + // This will be wired up to the existing logic in Phase 2 + await Task.CompletedTask; + } +} diff --git a/Vsix/ConvertVBToCSExtensibilityCommand.cs b/Vsix/ConvertVBToCSExtensibilityCommand.cs new file mode 100644 index 000000000..93ba48dfc --- /dev/null +++ b/Vsix/ConvertVBToCSExtensibilityCommand.cs @@ -0,0 +1,25 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Commands; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[VisualStudioContribution] +public class ConvertVBToCSExtensibilityCommand : Command +{ + private readonly CodeConverterPackage _package; + + public ConvertVBToCSExtensibilityCommand(CodeConverterPackage package) + { + _package = package; + } + + public override CommandConfiguration CommandConfiguration => new("%a3378a21-e939-40c9-9e4b-eb0cec7b7854%"); + + public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) + { + // This will be wired up to the existing logic in Phase 2 + await Task.CompletedTask; + } +} From 5c39c42af98764bd67340b3cd16de0f1cf2a3b4c Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 17:55:57 +0000 Subject: [PATCH 4/8] Phase 2: Add initial Extensibility SDK settings contribution --- Vsix/ConverterSettings.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Vsix/ConverterSettings.cs diff --git a/Vsix/ConverterSettings.cs b/Vsix/ConverterSettings.cs new file mode 100644 index 000000000..5b7acf5a9 --- /dev/null +++ b/Vsix/ConverterSettings.cs @@ -0,0 +1,23 @@ +using System.Runtime.Serialization; +using Microsoft.VisualStudio.Extensibility; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[DataContract] +public class ConverterSettings +{ + [DataMember] + public bool CopyResultToClipboardForSingleDocument { get; set; } + + [DataMember] + public bool AlwaysOverwriteFiles { get; set; } + + [DataMember] + public bool CreateBackups { get; set; } = true; + + [DataMember] + public int FormattingTimeoutMinutes { get; set; } = 15; + + [DataMember] + public bool BypassAssemblyLoadingErrors { get; set; } +} From afd4567bb50b8489dbf02ccbef832e532a7fb10f Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 23:48:04 +0000 Subject: [PATCH 5/8] Open up version compatibility --- Vsix/source.extension.vsixmanifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Vsix/source.extension.vsixmanifest b/Vsix/source.extension.vsixmanifest index 961647bf9..0325f30f9 100644 --- a/Vsix/source.extension.vsixmanifest +++ b/Vsix/source.extension.vsixmanifest @@ -13,10 +13,10 @@ code converter vb csharp visual basic csharp net translate - + amd64 - + arm64 From b0481d1a4d77e57b0153eecb41441202edb43d2e Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 23:53:37 +0000 Subject: [PATCH 6/8] Remove this reference which struggles to resolve --- Vsix/Vsix.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Vsix/Vsix.csproj b/Vsix/Vsix.csproj index 7645b6add..02e64e82d 100644 --- a/Vsix/Vsix.csproj +++ b/Vsix/Vsix.csproj @@ -1,4 +1,4 @@ - + net472 disable @@ -18,7 +18,6 @@ - From c39c03163b99a85950a596cad361cf88e135eb10 Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 1 Mar 2026 23:56:43 +0000 Subject: [PATCH 7/8] Phase 2: Wired up Extensibility commands to CodeConversion logic --- Vsix/CodeConverterPackage.cs | 5 +++++ Vsix/ConvertCSToVBExtensibilityCommand.cs | 24 +++++++++++++++++++++-- Vsix/ConvertVBToCSExtensibilityCommand.cs | 24 +++++++++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Vsix/CodeConverterPackage.cs b/Vsix/CodeConverterPackage.cs index 623878a81..cbcd058f4 100644 --- a/Vsix/CodeConverterPackage.cs +++ b/Vsix/CodeConverterPackage.cs @@ -86,6 +86,9 @@ public sealed class CodeConverterPackage : AsyncPackage public const string ConvertableSolutionMenuVisibilityGuid = "8e7192d0-28b7-4fe7-8d84-82c1db98d459"; internal Cancellation PackageCancellation { get; } = new(); + + internal static CodeConversion CodeConversionInstance { get; private set; } + internal static CodeConverterPackage Instance { get; private set; } /// /// Initializes a new instance of package class. @@ -110,6 +113,8 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var visualStudioWorkspace = componentModel.GetService(); var codeConversion = await CodeConversion.CreateAsync(this, visualStudioWorkspace, this.GetDialogPageAsync); + CodeConversionInstance = codeConversion; + Instance = this; ConvertCSToVBCommand.Initialize(this, oleMenuCommandService, codeConversion); ConvertVBToCSCommand.Initialize(this, oleMenuCommandService, codeConversion); PasteAsVB.Initialize(this, oleMenuCommandService, codeConversion); diff --git a/Vsix/ConvertCSToVBExtensibilityCommand.cs b/Vsix/ConvertCSToVBExtensibilityCommand.cs index b8ebae3ee..3d1bc3a19 100644 --- a/Vsix/ConvertCSToVBExtensibilityCommand.cs +++ b/Vsix/ConvertCSToVBExtensibilityCommand.cs @@ -19,7 +19,27 @@ public ConvertCSToVBExtensibilityCommand(CodeConverterPackage package) public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) { - // This will be wired up to the existing logic in Phase 2 - await Task.CompletedTask; + var codeConversion = CodeConverterPackage.CodeConversionInstance; + var serviceProvider = CodeConverterPackage.Instance; + if (codeConversion == null || serviceProvider == null) return; + + var itemsPath = await VisualStudioInteraction.GetSelectedItemsPathAsync(CodeConversion.IsCSFileName); + if (itemsPath.Count > 0) + { + await codeConversion.ConvertDocumentsAsync(itemsPath, cancellationToken); + return; + } + + var projects = await VisualStudioInteraction.GetSelectedProjectsAsync(".csproj"); + if (projects.Count > 0) + { + await codeConversion.ConvertProjectsAsync(projects, cancellationToken); + return; + } + + (string filePath, var selection) = await VisualStudioInteraction.GetCurrentFilenameAndSelectionAsync(serviceProvider, CodeConversion.IsCSFileName, false); + if (filePath != null && selection != null) { + await codeConversion.ConvertDocumentAsync(filePath, selection.Value, cancellationToken); + } } } diff --git a/Vsix/ConvertVBToCSExtensibilityCommand.cs b/Vsix/ConvertVBToCSExtensibilityCommand.cs index 93ba48dfc..1cc9fe3e7 100644 --- a/Vsix/ConvertVBToCSExtensibilityCommand.cs +++ b/Vsix/ConvertVBToCSExtensibilityCommand.cs @@ -19,7 +19,27 @@ public ConvertVBToCSExtensibilityCommand(CodeConverterPackage package) public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) { - // This will be wired up to the existing logic in Phase 2 - await Task.CompletedTask; + var codeConversion = CodeConverterPackage.CodeConversionInstance; + var serviceProvider = CodeConverterPackage.Instance; + if (codeConversion == null || serviceProvider == null) return; + + var itemsPath = await VisualStudioInteraction.GetSelectedItemsPathAsync(CodeConversion.IsVBFileName); + if (itemsPath.Count > 0) + { + await codeConversion.ConvertDocumentsAsync(itemsPath, cancellationToken); + return; + } + + var projects = await VisualStudioInteraction.GetSelectedProjectsAsync(".vbproj"); + if (projects.Count > 0) + { + await codeConversion.ConvertProjectsAsync(projects, cancellationToken); + return; + } + + (string filePath, var selection) = await VisualStudioInteraction.GetCurrentFilenameAndSelectionAsync(serviceProvider, CodeConversion.IsVBFileName, false); + if (filePath != null && selection != null) { + await codeConversion.ConvertDocumentAsync(filePath, selection.Value, cancellationToken); + } } } From e596706b3e2b8c74a7d1cc10a3742ed1cd4a7211 Mon Sep 17 00:00:00 2001 From: Graham Date: Mon, 2 Mar 2026 00:19:41 +0000 Subject: [PATCH 8/8] Remove unused --- Vsix/ConverterSettings.cs | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 Vsix/ConverterSettings.cs diff --git a/Vsix/ConverterSettings.cs b/Vsix/ConverterSettings.cs deleted file mode 100644 index 5b7acf5a9..000000000 --- a/Vsix/ConverterSettings.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Runtime.Serialization; -using Microsoft.VisualStudio.Extensibility; - -namespace ICSharpCode.CodeConverter.VsExtension; - -[DataContract] -public class ConverterSettings -{ - [DataMember] - public bool CopyResultToClipboardForSingleDocument { get; set; } - - [DataMember] - public bool AlwaysOverwriteFiles { get; set; } - - [DataMember] - public bool CreateBackups { get; set; } = true; - - [DataMember] - public int FormattingTimeoutMinutes { get; set; } = 15; - - [DataMember] - public bool BypassAssemblyLoadingErrors { get; set; } -}