更新 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 2022 之前,可以通过简单的 <Reference Include="Newtonsoft.Json" /> 引用发现一些不是 Visual Studio SDK 独有的程序集(例如,Newtonsoft.Json.dll)。 但是在 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 中设置为 True

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

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

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

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

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

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

  4. 对于托管的 Visual Studio 扩展,请在 Visual Studio 2022 目标项目文件中将包引用从 16.x(或更早版本)更新为 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 将无法安装扩展。

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

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

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

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 没有允许基于预处理器符号自定义内容的预处理器。 可能需要复制和维护两个内容不同于 Visual Studio 2022 和早期版本的 XAML 页面。

某些情况下,对存在于 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 文件中。

按照映像优化器的分步示例操作,其中包含到项目的链接以及每个步骤的代码更改。