更新适用于 Visual Studio 2022 的 Visual Studio 扩展

重要

本文中的建议可指导开发人员迁移需要重大更改才能在 Visual Studio 2019 和 Visual Studio 2022 中工作的扩展。 在这些情况下,我们建议你有两个 VSIX 项目和条件编译。

许多扩展只需进行微小的更改即可同时在 Visual Studio 2019 和 Visual Studio 2022 中使用,无需遵循本文中关于改进扩展的建议。 在 Visual Studio 2022 中试用扩展,并评估最适合扩展的选项。

Visual Studio 2022 是一个 64 位应用程序,在 Visual Studio SDK 中引入了一些中断性变更。 本文将指导你完成使扩展使用 Visual Studio 2022 当前预览版所需的步骤。 然后,可以在 Visual Studio 2022 正式发布之前为用户安装扩展做好准备。

安装 Visual Studio 和编译扩展

Visual Studio 2022 下载页面安装 Visual Studio 2022。

以 .NET 语言编写的扩展

面向 Visual Studio 2022 的托管扩展的 Visual Studio SDK 在 NuGet 上独家提供:

即使未引用任何中断性变更,扩展 也必须 使用 任何 CPUx64 平台进行编译。 x86 平台与 Visual Studio 2022 中的 64 位进程不兼容。

用 C++ 编写的扩展

使用 C++ 编译的用于扩展的 Visual Studio SDK 随已安装的 Visual Studio SDK 一样可用。

即使你没有引用任何重大变更,扩展也必须专门针对 Visual Studio 2022 SDK 和 AMD64 编译。

具有运行代码的扩展

正在运行代码的扩展需要专门为 Visual Studio 2022 编译。 Visual Studio 2022 不会加载面向早期版本的 Visual Studio 的任何扩展。

了解如何将早期 Visual Studio 版本的扩展迁移到 Visual Studio 2022:

  1. 使项目现代化
  2. 将源代码重构到共享项目中,以兼容 Visual Studio 2022 和更早版本。
  3. 添加面向 Visual Studio 2022 的 VSIX 项目包/程序集映射表
  4. 进行必要的代码调整
  5. 测试 Visual Studio 2022 扩展
  6. 发布 Visual Studio 2022 扩展

没有运行代码的扩展

不包含任何正在运行的代码(例如项目或项模板)的扩展不需要执行上述步骤,包括生成两个不同的 VSIX。

而是修改一个 VSIX,使其 source.extension.vsixmanifest 文件声明两个安装目标:

<Installation>
   <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[15.0,17.0)">
      <ProductArchitecture>x86</ProductArchitecture>
   </InstallationTarget>
   <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,18.0)">
      <ProductArchitecture>amd64</ProductArchitecture>
   </InstallationTarget>
</Installation>

可以跳过本文中有关使用共享项目和多个 VSIX 的步骤。 可以继续 测试

注释

如果要使用 Visual Studio 2022 创作 新的 Visual Studio 扩展,并且想要同时面向 Visual Studio 2019 或早期版本,请参阅 本指南

MSBuild 任务

如果你创作 MSBuild 任务,请注意,在 Visual Studio 2022 中,它们很可能在 64 位 MSBuild.exe 进程中加载。 如果任务需要 32 位进程才能运行,请参阅 “配置目标和任务 ”,以确保 MSBuild 在 32 位进程中加载任务。

将您的 VSIX 项目现代化

在将 Visual Studio 2022 支持添加到扩展之前,强烈建议清理和现代化现有项目:

  1. 从 packages.config 迁移到 PackageReference

  2. 将任何直接 Visual Studio SDK 程序集引用替换为 PackageReference 项:

    -<Reference Include="Microsoft.VisualStudio.OLE.Interop" />
    +<PackageReference Include="Microsoft.VisualStudio.OLE.Interop" Version="..." />
    

    小窍门

    可以将 许多 程序集引用替换为一个“元包”实例:

    -<Reference Include="Microsoft.VisualStudio.OLE.Interop" />
    -<Reference Include="Microsoft.VisualStudio.Interop" />
    -<Reference Include="Microsoft.VisualStudio.Interop.8.0" />
    +<PackageReference Include="Microsoft.VisualStudio.Sdk" Version="..." />
    

    请确保选择的包版本与所针对的 Visual Studio 最低版本一致。

某些并非 Visual Studio SDK 专有的程序集(例如 Newtonsoft.Json.dll)可能通过 Visual Studio 2022 之前的简单 <Reference Include="Newtonsoft.Json" /> 引用被发现。 但在 Visual Studio 2022 中,它们需要包引用。 原因是某些 Visual Studio 运行时和 SDK 目录已从 MSBuild 中的默认程序集搜索路径中删除。

从直接程序集引用切换到 NuGet 包引用时,可能会获取其他程序集引用和分析器包,因为 NuGet 会自动安装依赖项的传递闭包。 这通常是正常的,但它可能会在构建过程中生成其他警告。 请处理这些警告并尽可能多地解决它们。 请考虑使用代码 #pragma warning disable <id> 内区域来禁止显示无法解析的警告。

将共享项目用于多目标开发

共享项目是在 Visual Studio 2015 中引入的项目类型。 Visual Studio 中的共享项目允许在多个项目之间共享源代码文件,并使用条件编译符号和唯一引用集以不同的方式生成。

Visual Studio 2022 需要一套与所有早期 Visual Studio 版本不同的引用程序集。 因此,我们建议使用共享项目方便地将扩展多目标定位到 Visual Studio 2022、早期版本和更高版本。 此方法将为你提供代码共享,但提供不同的引用。

在 Visual Studio 扩展的上下文中,可以为 Visual Studio 2022 及更高版本创建一个 VSIX 项目,以及 Visual Studio 2019 及更早版本的一个 VSIX 项目。 其中每个项目仅包含一个 source.extension.vsixmanifest 实例和包对 16.x SDK 或 17.x SDK 的引用。 这些 VSIX 项目还将具有对新的共享项目的共享项目引用,该项目将托管可在两个 Visual Studio 版本中共享的所有源代码。

本部分假定你已有一个面向 Visual Studio 2019 的 VSIX 项目,并且希望扩展在 Visual Studio 2022 上正常工作。

可以使用 Visual Studio 2019 完成所有这些步骤:

  1. 如果尚未这样做, 请使项目现代化 ,以简化此更新过程中的后续步骤。

  2. 为每个引用 Visual Studio SDK 的现有项目将一个新的共享项目添加到解决方案中。 右键单击解决方案,然后选择“ 添加新>项目”。

    显示添加新项目的选择的屏幕截图。

  3. 在“ 添加新项目 ”对话框中,搜索 共享项目,然后选择 “共享项目 ”模板。

    显示搜索并选择“共享项目”模板的屏幕截图。

  4. 将每个 Visual Studio SDK 引用项目的引用添加到其共享项目对应项。

    显示用于添加共享项目引用的选择的屏幕截图。

  5. 将所有源代码(包括 .cs.resx 文件)从每个 Visual Studio SDK 引用项目移动到其共享项目对应项。 将 source.extension.vsixmanifest 文件保留在 VSIX 项目中。

    显示包含所有源文件的共享项目的屏幕截图。

  6. 将元数据文件(例如发行说明、许可证和图标)和 VSCT 文件移动到共享目录。 然后将其作为链接文件添加到 VSIX 项目。 请注意,共享目录与共享项目分开。

    显示将元数据和 V S C T 文件添加为链接文件的选项的屏幕截图。

    • 对于元数据文件,请将“生成操作”设置为“内容”。 将 VSIX 中的 Include 设置为 True

      显示如何在 V S I X 中包含元数据文件的屏幕截图。

    • 对于 VSCT 文件,请将 生成操作 设置为 VSCTCompile。 将 VSIX 中的 Include 设置为 False

      显示 V S C T 文件的所选属性的屏幕截图。

      如果 Visual Studio 提示此设置不受支持,您可以通过卸载项目然后将生成操作从Content更改为VSCTCompile来手动更改:

      -<Content Include="..\SharedFiles\VSIXProject1Package.vsct">
      -  <Link>VSIXProject1Package.vsct</Link>
      -</Content>
      +<VSCTCompile Include="..\SharedFiles\VSIXProject1Package.vsct">
      +  <Link>VSIXProject1Package.vsct</Link>
      +  <ResourceName>Menus.ctmenu</ResourceName>
      +</VSCTCompile>
      
  7. 构建项目以确保没有引入任何错误。

项目现已准备好添加 Visual Studio 2022 支持。

添加 Visual Studio 2022 目标

本部分假定你已完成将 你的 Visual Studio 扩展重构为与共享项目结合的步骤。

使用以下步骤将 Visual Studio 2022 支持添加到扩展。 可以使用 Visual Studio 2019 完成它们。

  1. 向解决方案添加新的 VSIX 项目。 此项目将面向 Visual Studio 2022。 删除模板附带的任何源代码,但保留 source.extension.vsixmanifest 文件。

  2. 在您的新 VSIX 项目中,添加对与目标为 Visual Studio 2019 的 VSIX 相同的共享项目的引用。

    显示包含一个共享项目和两个 V S I X 项目的解决方案的屏幕截图。

  3. 验证新的 VSIX 项目是否已正确生成。 可能需要添加引用以匹配原始 VSIX 项目,以解决任何编译器错误。

  4. 对于托管的 Visual Studio 扩展,请将包引用从 16.x(或更早版本)更新到 Visual Studio 2022 目标项目文件中的 17.x 包版本。 使用 NuGet 包管理器或直接编辑项目文件:

    -<PackageReference Include="Microsoft.VisualStudio.SDK" Version="16.0.206" />
    +<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.0" />
    -<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="16.10.32" />
    +<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.0" />
    

    上述代码中显示的版本仅用于演示。 在代码中,使用 NuGet 网站提供的版本。

    在许多情况下,包 ID 已更改。 有关 Visual Studio 2022 中的更改列表,请参阅 包/程序集映射表

    C++中编写的扩展尚没有可供其编译的 SDK。

  5. 对于C++项目,必须为 AMD64 编译扩展。 对于托管扩展,请考虑将项目从构建为任意 CPU更改为面向x64。 此更改可确保在 Visual Studio 2022 中,扩展始终在 64 位进程中加载。 任何 CPU 也没问题,但如果引用任何仅限 x64 的本机二进制文件,它可能会生成警告。

    您的扩展在本机模块上可能具有的任何依赖项都必须从 x86 映像更新为 AMD64 映像。

  6. 编辑 source.extension.vsixmanifest 文件以反映面向 Visual Studio 2022 的目标。 设置 <InstallationTarget> 标记以指示 Visual Studio 2022。 设置元素 ProductArchitecture 以指示 AMD64 有效负载。

    <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,18.0)">
       <ProductArchitecture>amd64</ProductArchitecture>
    </InstallationTarget>
    

    重要

    在 Visual Studio 2019 中,此文件的设计器不会公开新 ProductArchitecture 元素。 需要使用 XML 编辑器进行此更改。 若要访问 XML 编辑器,请转到解决方案资源管理器并选择 “打开方式 ”命令。

    元素 ProductArchitecture 至关重要。 Visual Studio 2022 不会在没有必要条件的情况下安装您的扩展。

    元素 价值 Description
    ProductArchitecture x86amd64 此 VSIX 支持的平台。 不区分大小写。 每个元素使用一个平台,每个 InstallationTarget 实例使用一个元素。 对于小于 17.0 的产品版本,默认值是 x86 可以省略的。 对于产品版本 17.0 及更高版本,此元素是必需的,并且没有默认值。 对于 Visual Studio 2022,此元素的唯一有效内容是 amd64
  7. source.extension.vsixmanifest 中进行任何必要的其他调整,以匹配面向 Visual Studio 2019(如果有)的调整。

    如果要发布两个面向不同版本的 Visual Studio 的扩展,请确保清单元素中的 Identity VSIX ID 对于每个扩展都是不同的。

此时,你有一个面向 Visual Studio 2022 的 VSIX 扩展。 应生成面向 Visual Studio 2022 的 VSIX 项目,并解决出现的任何生成中断。 如果在面向 Visual Studio 2022 的 VSIX 项目中没有构建失败,恭喜! 你已准备好进行测试。

处理重大API变更

重大 API 更改可能需要更新在早期版本的 Visual Studio 上运行的代码。 有关如何更新代码的提示,请参阅 Visual Studio 2022 中的中断性 API 更改

调整代码时,建议使用 条件编译。 然后,代码可以继续支持早期 Visual Studio 版本,同时添加对 Visual Studio 2022 的支持。

完成针对 Visual Studio 2022 的扩展构建后,继续测试。

使用条件编译符号

如果想要对 Visual Studio 2022 和早期版本使用相同的源代码(即使是相同的文件),则可能需要使用条件编译。 然后,可以分叉代码以适应重大更改。 条件编译是 C#、Visual Basic 和 C++ 语言的一项功能。 它可用于共享大多数代码,同时容纳特定位置的不同 API。

有关使用预处理器指令和条件编译符号的详细信息,请参阅 C# 预处理器指令

面向早期 Visual Studio 版本的工程需使用条件编译符号。 然后,可以使用此符号来分叉代码以使用不同的 API。 可以在项目属性页上设置条件编译符号:

显示用于输入条件编译符号的框的屏幕截图。

请务必为所有 配置设置编译符号。 默认情况下,输入的符号可能仅适用于一个配置。

C# 技术

可以使用编译符号作为预处理器指令(#if),如以下代码所示。 然后,可以派生代码来处理 Visual Studio 版本之间的不兼容变更。

    Guid myGuid = new Guid("{633FBA02-719B-40E7-96BF-0899767CD104}");
    uint myFlags = 0;
    IVsShell shell = await AsyncServiceProvider.GlobalProvider.GetServiceAsync<SVsShell, IVsShell>();
#if Dev16
    shell.LoadUILibrary(myGuid, myFlags, out uint ptrLib);
#else
    shell.LoadUILibrary(myGuid, myFlags, out IntPtr ptrLib);
#endif

在某些情况下,可以通过使用 var 来避免命名类型,并避免需要 #if 区域。 前面的代码片段也可以编写为:

    Guid myGuid = new Guid("{633FBA02-719B-40E7-96BF-0899767CD104}");
    uint myFlags = 0;
    IVsShell shell = await AsyncServiceProvider.GlobalProvider.GetServiceAsync<SVsShell, IVsShell>();
    shell.LoadUILibrary(myGuid, myFlags, out var ptrLib);

使用 #if 语法时,请注意如何使用语言服务上下文的下拉列表来更改语法突出显示。 另一个下拉列表可帮助语言服务关注此扩展的目标 Visual Studio 版本,而不是另一个目标 Visual Studio 版本。

显示共享项目中的条件编译的屏幕截图。

XAML 共享技术

XAML 没有预处理器,允许基于预处理器符号自定义内容。 可能需要复制和维护两个 XAML 页面,其内容在 Visual Studio 2022 和更低版本之间有所不同。

在某些情况下,Visual Studio 2022 和更早版本中的不同程序集包含的类型引用可能仍然可以在一个 XAML 文件中表示。 删除引用程序集的命名空间:

-xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
-Value="{DynamicResource {x:Static vsui:TreeViewColors.SelectedItemActiveBrushKey}}"
+Value="{DynamicResource TreeViewColors.SelectedItemActiveBrushKey}"

测试扩展

若要测试面向 Visual Studio 2022 的扩展,需要安装 Visual Studio 2022。 无法在早期版本的 Visual Studio 上运行 64 位扩展。

可以使用 Visual Studio 2022 生成和测试扩展,无论它们面向 Visual Studio 2022 还是早期版本。 从 Visual Studio 2022 打开 VSIX 项目时,Visual Studio 的实验实例随即打开。

强烈建议使用希望扩展支持的每个 Visual Studio 版本进行测试。

发布扩展

你已将 Visual Studio 2022 目标添加到扩展并对其进行测试。 现在,你已准备好发布扩展,供世界欣赏。

Visual Studio Marketplace

将扩展发布到 Visual Studio Marketplace 是让新用户查找和安装扩展的好方法。 无论你的扩展是专门面向 Visual Studio 2022 还是面向较旧的 Visual Studio 版本,市场都支持你。

未来,应用市场将允许将多个 VSIX 上传到一个列表中。 然后,您可以上传适用于 Visual Studio 2022 的 VSIX 以及适用于早期版本 Visual Studio 的 VSIX。 当用户使用 Visual Studio 扩展管理器时,他们将自动获得与其已安装的 Visual Studio 版本相匹配的正确 VSIX。

自定义安装程序

如果您生成 MSI 或 EXE 文件来安装您的扩展并启动 vsixinstaller.exe 来安装(部分)扩展,请注意 Visual Studio 2022 中的 VSIX 安装程序已更新。 开发人员需要使用 Visual Studio 2022 附带的 VSIX 安装程序版本来安装该版本的 Visual Studio 扩展。

Visual Studio 2022 中的 VSIX 安装程序还会安装适用于与 Visual Studio 2022 一起存在于同一台计算机上的 Visual Studio 早期版本的扩展。

网络共享

可以通过 LAN 或任何其他方式共享扩展。 如果面向 Visual Studio 2022 和更早版本,则需要单独共享多个 VSIX。 为用户提供文件名(或将它们放置在唯一文件夹中),以帮助用户知道根据安装的 Visual Studio 版本安装哪些 VSIX。

依赖关系

如果 VSIX 通过 <dependency> 元素将其他 VSIX 指定为依赖项,则需要将每个引用的 VSIX 安装在与 VSIX 相同的目标和产品体系结构中。 如果依赖 VSIX 不支持 Visual Studio 的目标安装,VSIX 将失败。

依赖的 VSIX 可以支持比你的更多的目标和体系结构,但不能少。 此限制意味着 VSIX 的部署和分发方法应反映其依赖项的部署和分发方法。

问题解答

:我的扩展不需要任何互作性更改,因为它只是提供数据(例如模板)。 是否可以创建包含 Visual Studio 2022 的单个扩展?

:是的! 有关此的更多信息,请参阅 扩展而不运行代码

:NuGet 依赖项引入旧的互操作性程序集并导致类冲突。 我该怎么办?

:将以下行添加到 .csproj 文件以避免重复程序集:

    <PackageReference Include="<Name of offending assembly>" ExcludeAssets="compile" PrivateAssets="all" />

此代码将阻止包引用从其他依赖项导入程序集的旧版本。

:我的命令和热键在将源文件切换到共享项目后停止在 Visual Studio 中工作。 我该怎么办?

:图像优化器示例 的步骤 2.4 演示如何将 VSCT 文件添加为链接项,以便将其编译到 VSCT 文件中。

请您按照分步示例 ImageOptimizer 进行操作,其中每个步骤都提供了项目和代码更改的链接。