更新 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="..." />
    

    提示

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

    -<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 的每个现有项目将新的共享项目添加到解决方案。 右键单击解决方案,然后选择“添加新>项目”。

    Screenshot that shows the selections for adding a new project.

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

    Screenshot that shows searching for and selecting the Shared Project template.

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

    Screenshot that shows selections for adding a shared project reference.

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

    Screenshot that shows a shared project containing all source files.

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

    Screenshot that shows selections for adding metadata and V S C T files as linked files.

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

      Screenshot that shows including metadata files in V S I X.

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

      Screenshot that shows selected properties for a V S C T file.

      如果 Visual Studio 抱怨此设置不受支持,可以通过卸载项目并更改为ContentVSCTCompile

      -<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 引用的同一共享项目的引用。

    Screenshot that shows a solution with one shared project and two V S I X projects.

  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 编辑器,请转到解决方案资源管理器并选择“打开 With”命令。

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

    元素 说明
    ProductArchitecture x86, amd64 此 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。 可以在项目属性页上设置条件编译符号:

Screenshot that shows the box for entering a conditional compilation symbol.

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

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 版本。

Screenshot that shows conditional compilation in a shared project.

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 的分步示例操作,其中包含每个步骤的项目和代码更改的链接。