准备打包桌面应用程序

本文列出了在打包桌面应用程序之前需要知道的事项。 可能不需要执行很多操作即可使应用为打包过程做好准备,但是如果以下任意一项适用于你的应用程序,则在打包之前需要解决该问题。

  • .NET 应用程序需要低于 4.6.2 的 .NET Framework 版本。 如果你正在打包 .NET 应用程序,我们建议使应用程序以 .NET Framework 4.6.2 或更高版本为目标。 Windows 10 版本 1607(也称为周年更新)中首次引入了安装和运行打包桌面应用程序的功能,此 OS 版本默认包含 .NET Framework 4.6.2。 更高版本的 OS 包含更高版本的 .NET Framework。 有关更高版本的 Windows 10 中包含的 .NET 版本完整列表,请参阅此文

    在大多数情况下,预期都可以在打包的桌面应用程序中以低于 4.6.2 的 .NET Framework 版本为目标。 但是,如果以低于 4.6.2 的版本为目标,则在将打包的桌面应用程序分发给用户之前,应先对其进行全面测试。

    • 4.0 - 4.6.1:以这些 .NET Framework 版本为目标的应用程序在 4.6.2 或更高版本中预期也可以正常运行。 因此,在 Windows 10 版本 1607 或更高版本上使用 OS 原装 .NET Framework 版本的情况下,这些应用程序应该无需进行任何更改即可安装和运行。

    • 2.0 - 3.5:根据我们的测试,以这些 .NET Framework 版本为目标的打包桌面应用程序通常可以正常运行,但某些情况下可能会出现性能问题。 要使这些打包的应用程序能够安装和运行,必须在目标计算机上安装 .NET Framework 3.5 功能(此功能还包括 .NET Framework 2.0 和 3.0)。 打包这些应用程序后,还应该对其进行全面的测试。

  • 应用程序始终使用提升的安全特权运行。 应用程序需要在以交互用户身份运行时工作。 安装应用程序的用户可能不是系统管理员,因此需要应用程序以提升的权限运行意味着它无法对标准用户正确运行。 如果打算将应用发布到 Mcirosoft Store,请注意,Store 不接受任何功能部分需要提升权限的应用。

  • 应用程序需要 Windows 驱动程序。 MSIX 不支持 Windows 驱动程序。

  • 应用程序需要用户 Windows 服务。 MSIX 不支持每用户 Windows 服务。 MSIX 支持在定义的系统帐户之一(LocalSystem、LocalService 或 NetworkService)下运行的会话 0(每台计算机)服务。 请使用后台任务,而不是用户 Windows 服务。

  • 在进程内将应用的模块加载到不在 Windows 应用包中的进程。 不允许这样做,这意味着进程内扩展(如 shell 扩展)不受支持。 但是,如果同一包中有两个应用,则可以在它们之间进行进程间通信。

  • 确保应用程序安装的任何扩展安装在应用程序所安装到的位置。 Windows 允许用户和 IT 管理者更改包的默认安装位置。 查看“设置”->“系统”->“存储”->“更多存储设置”->“更改新内容的保存位置”->“新应用将保存到”。 如果在应用程序中安装某个扩展,请确保该扩展在安装文件夹方面没有其他限制。 例如,某些扩展可能会禁止将其扩展安装到非系统驱动器。 如果默认位置已更改,这会导致错误 0x80073D01 (ERROR_DEPLOYMENT_BLOCKED_BY_POLICY)。

  • 应用程序使用自定义应用程序用户模型 ID (AUMID)。 如果进程调用 SetCurrentProcessExplicitAppUserModelID 以设置其自己的 AUMID,则它可能仅使用应用程序模型环境/Windows 应用包为其生成的 AUMID。 不能定义自定义 AUMID。

  • 应用程序修改 HKEY_LOCAL_MACHINE (HKLM) 注册表配置单元。 应用程序的任何创建 HKLM 键或打开一个键以进行修改的尝试都会导致拒绝访问失败。 请记住,应用程序具有自身的注册表专用虚拟化视图,因此用户范围和计算机范围的注册表配置单元的概念(HKLM 的定义)不适用。 你需要寻找其他方法来实现过去使用 HKLM 实现的效果,例如改为写入到 HKEY_CURRENT_USER (HKCU)。

  • 应用程序使用 ddeexec 注册表子项作为启动另一个应用的方式。 请改为使用应用包清单中各种可激活的*扩展配置的其中一个 DelegateExecute 谓词处理程序。

  • 应用程序会写入 AppData 文件夹或注册表,目的是与其他应用共享数据。 转换后,AppData 将重定向到本地应用数据存储,该存储是每个应用的专用应用商店。

    应用程序将写入 HKEY_LOCAL_MACHINE 注册表配置单元的所有条目都将重定向到隔离的二进制文件中,应用程序写入 HKEY_CURRENT_USER 注册表配置单元的任何条目都将按用户、按应用放入专用位置。 有关文件和注册表重定向的更多详细信息,请参阅在桌面桥幕后

    使用不同的进程间数据共享方式。 有关详细信息,请参阅存储和检索设置以及其他应用数据

  • 应用程序写入应用的安装目录。 例如,应用程序写入与你的 exe 放置在同一个目录中的日志文件。 不支持此功能,因此需要找到其他位置,例如本地应用数据存储。

  • 应用程序使用当前工作目录。 在运行时,打包的桌面应用程序不会获得先前在桌面 .LNK 快捷方式中指定的相同工作目录。 如果具有正确的目录对应用程序正常运行很重要,需要在运行时更改 CWD。

    注意

    如果应用需要写入安装目录或使用当前工作目录,则你还可以考虑将一个使用包支持框架的运行时修复程序添加到包中。 有关详细信息,请参阅本文

  • 应用程序安装需要用户交互。 应用程序安装程序必须能够在无提示的情况下运行,并且必须安装默认不在干净 OS 映像中的所有必备组件。

  • 应用程序公开 COM 对象。 来自程序包内的进程和扩展可以注册并使用 COM 和 OLE 服务器,进程内和进程外 (OOP) 皆可。 创意者更新添加了打包的 COM 支持,它提供注册 OOP COM 和 OLE 服务器(现在这些服务器在包外部可见)的功能。 请参阅对桌面桥的 COM 服务器和 OLE 文档支持

    打包的 COM 支持适用于现有的 COM API,但不适用于依赖直接读取注册表的应用程序扩展,因为打包的 COM 位于一个专用位置。

  • 应用程序公开 GAC 程序集以供其他进程使用。 应用程序无法公开 GAC 程序集以供来自 Windows 应用包外部可执行文件的进程使用。 来自包内部的进程可以照常注册和使用 GAC 程序集,但它们在外部将不可见。 这意味着如果由外部进程调用,则 OLE 等互操作应用场景将不起作用。

  • 应用程序正以不受支持的方式链接 C 运行时库 (CRT)。 Microsoft C/C++ 运行时库为 Microsoft Windows 操作系统的编程提供了例程。 这些例程自动执行许多不采用 C 和 C++ 语言提供的常见编程任务。 如果应用程序利用 C/C++ 运行时库,则你需要确保它以受支持的方式链接。

    对于最新版本的 CRT,Visual Studio 2017 即支持静态和动态链接,以允许代码使用常见 DLL 文件,也支持静态链接,以将库直接链接到代码。 如果可能,我们建议让应用程序将动态链接与 VS 2017 一起使用。

    在以前版本的 Visual Studio 中支持。 有关详细信息,请参阅下表:

    Visual Studio 版本动态链接静态链接
    2005 (VC 8)不支持支持
    2008 (VC 9)不支持支持
    2010 (VC 10)支持支持
    2012 (VC 11)支持不支持
    2013 (VC 12)支持不支持
    2015 和 2017 (VC 14)支持支持

    注意:在所有情况下,都必须链接到最新公开发布的 CRT。

  • 应用程序从 Windows 并行文件夹安装和加载程序集。 例如,应用程序使用 C 运行时库 VC8 或 VC9,并且正在从 Windows 并行文件夹动态链接它们,这意味着代码正在使用来自共享文件夹的常见 DLL 文件。 此操作不受支持。 需要通过将可再发生库文件直接链接到代码中来实现静态链接。

  • 应用程序使用 System32/SysWOW64 文件夹中的依赖项。 若要使这些 DLL 有效,必须将其包含在 Windows 应用包的虚拟文件系统部分中。 这可确保应用程序的行为就像 DLL 已安装在 System32/SysWOW64 文件夹中一样。 在包的根目录中创建一个名为“VFS”的文件夹。 在该文件夹中创建 SystemX64SystemX86 文件夹。 然后,将 DLL 的 32 位版本放入 SystemX86 文件夹,将 64 位版本放入 SystemX64 文件夹。

  • 应用程序使用 VCLibs 框架包。 如果转换 C++ Win32 应用,必须处理 Visual C++ Runtime 的部署。 Visual Studio 2019 和 Windows SDK 在以下文件夹中包含 Visual C++ Runtime 版本 11.0、12.0 和14.0 的最新框架包:

    • VC 14.0 框架包:C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs.Desktop\14.0

    • VC 12.0 框架包:C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs.Desktop.120\14.0

    • VC 11.0 框架包:C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs.Desktop.110\14.0

    若要使用其中的一个包,必须在包清单中以依赖项的形式引用该包。 当客户从 Microsoft Store 安装零售版应用时,将连同该应用一起从 Store 安装该包。 如果旁边加载应用,则不会安装依赖项。 若要手动安装依赖项,必须使用位于上面所列安装文件夹中的、适用于 x86、x64 或 ARM 的相应 .appx 包来安装相应的框架包。

    若要在应用中引用 C++ Visual Runtime 框架包:

    1. 转到上面所列的、适用于应用所用 Visual C++ Runtime 版本的框架包安装文件夹。

    2. 打开该文件夹中的 SDKManifest.xml 文件,找到 FrameworkIdentity-DebugFrameworkIdentity-Retail 属性(取决于使用的是运行时调试版还是零售版),然后复制该属性中的 NameMinVersion 值。 例如,下面是当前 VC 14.0 框架包的 FrameworkIdentity-Retail 属性。

      FrameworkIdentity-Retail = "Name = Microsoft.VCLibs.140.00.UWPDesktop, MinVersion = 14.0.27323.0, Publisher = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'"
      
    3. 在应用包清单中的 <Dependencies> 节点下,添加以下 <PackageDependency> 元素。 确保将 NameMinVersion 值替换为在上一步骤中复制的值。 以下示例指定当前版本的 VC 14.0 框架包的依赖项。

      <PackageDependency Name="Microsoft.VCLibs.140.00.UWPDesktop" MinVersion="14.0.27323.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
      
  • 应用程序包含自定义跳转列表。 使用跳转列表时需要注意几个问题和事项。

    • 应用的体系结构与 OS 不匹配。 如果应用程序与 OS 体系结构不匹配(例如在 x64 Windows 上运行 x86 应用程序),则跳转列表目前无法正常工作。 当前没有其他解决方法,只能重新编译应用程序,使其匹配体系结构。

    • 应用程序创建跳转列表条目并调用 ICustomDestinationList::SetAppIDSetCurrentProcessExplicitAppUserModelID。 不要以编程方式在代码中设置 AppID。 这样做会导致跳转列表条目不显示。 如果应用程序需要自定义的 ID,请使用清单文件指定。 有关说明,请参阅手动打包桌面应用程序。 应用程序的 AppID 在 YOUR_PRAID_HERE 部分中指定。

    • 应用程序添加跳转列表 shell 链接,该链接引用包中的可执行文件。 你不能通过跳转列表直接启动程序包中的可执行文件(应用自身 .exe 的绝对路径除外)。 改为注册应用执行别名(此别名允许通过关键字启动打包的桌面应用程序,就像它在 PATH 环境变量中一样),并设置指向别名的链接目标路径。 有关如何使用 appExecutionAlias 扩展的详细信息,请参阅将桌面应用程序与 Windows 10 集成。 请注意,如果需要跳转列表中的链接的资产匹配原始 .exe,需要使用 SetIconLocation,以及你希望其他自定义条目使用的显示名称设置图标等资产。

    • 应用程序添加跳转列表条目,该条目通过绝对路径引用应用包中的资源。 更新应用程序的包时,应用程序的安装路径可能会更改,从而更改资源的位置(例如图标、文档、可执行文件等)。 如果跳转列表条目通过绝对路径引用此类资源,则应用程序应定期刷新其跳转列表(例如应用程序启动时)以确保正确解析路径。 或者,改为使用 UWP Windows.UI.StartScreen.JumpList API,这些 API 可让你引用使用包相对 ms-resource URI 方案(同时也是语言、DPI 和留意高对比度)的字符串和图像资产。

  • 应用程序启动一个实用工具来执行任务。 避免启动 PowerShell 和 Cmd.exe 等命令实用工具。 实际上,如果用户将应用程序安装在运行 Windows 10 S 的系统上,则应用程序根本无法启动这些实用工具。 这可能会使应用程序无法提交到 Microsoft Store,因为提交到 Microsoft Store 的所有应用都必须与 Windows 10 S 兼容。

    启动实用工具通常可以提供一种方便的方法,用于从操作系统获取信息、访问注册表或访问系统功能。 但是,可以改用 UWP API 来完成此类任务。 这些 API 的性能更强,因为它们无需单独的可执行文件即可运行,但更重要的是,它们会阻止应用程序访问包的外部。 应用的设计与打包的应用随附的隔离、信任和安全性保持一致,并且应用程序将按预期在运行 Windows 10 S 的系统上运行。

  • 应用程序托管加载项、插件或扩展。 在许多情况下,只要尚未对扩展打包并且该扩展以完全信任方式安装,COM 样式的扩展可能会继续工作。 这是因为那些安装程序可以使用其完全信任的功能修改注册表,并将扩展文件放置在主机应用程序应找到这些文件的任意位置。

    但是,如果这些扩展已打包,然后作为 Windows 应用包安装,则它们将无法正常工作,因为每个包(主机应用程序和扩展)将彼此隔离。 有关如何从系统隔离应用程序的详细信息,请参阅在桌面桥幕后

    用户安装到运行 Windows 10 S 的系统上的所有应用程序和扩展都必须作为 Windows 应用包安装。 因此,如果想要对扩展打包,或者打算鼓励你的参与者对其打包,请考虑如何能够促进主机应用程序包和任意扩展包之间的通信。 使用应用服务即可实现此目的。

  • 应用程序生成代码。 应用程序可以生成其在内存中使用的代码,但请避免将生成的代码写入磁盘,因为 Windows 应用认证过程在应用提交之前无法验证该代码。 此外,向磁盘写入代码的应用将无法在运行 Windows 10 S 的系统中正常运行。这可能会使应用程序无法提交到 Microsoft Store,因为提交到 Microsoft Store 的所有应用都必须与 Windows 10 S 兼容。

重要

创建 Windows 应用包后,请测试应用程序,确保它可以在运行 Windows 10 S 的系统上正常工作。所有提交到 Microsoft Store 的应用必须与 Windows 10 S 兼容。Microsoft Store 不接受不兼容的应用。 请参阅测试适用于 Windows 10 S 的 Windows 应用