乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发 - 传统应用通过稀疏包(Sparse Package)插上现代的翅膀

传统应用通过稀疏包(Sparse Package)插上现代的翅膀

image

许多Windows 10/11可扩展性功能需要在非UWP桌面应用中使用程序包标识符,包括后台任务(BackgroundTasks)通知(Notifications)动态磁贴(LiveTiles)共享目标(Share)。 对于这些情况OS需要使用标识来识别相应API的调用方。

image

在Windows 10版本v2004之前的OS发行版中,向桌面应用授予标识符的唯一方式是将该应用打包到已签名的MSIX包中。对于这些应用,将在程序包清单中指定标识,并由MSIX部署管道根据清单中的信息处理标识注册。程序包清单中引用的所有内容都存在于MSIX包中

image

从Windows 10版本v2004开始,可以通过生成稀疏包并将其注册到应用,向未打包到MSIX包中的桌面应用授予包标识符。通过此支持,尚不能采用MSIX打包方式进行部署的桌面应用可以使用需要程序包标识符的Windows 10/11可扩展性功能

需要包标识的功能(新式Windows 10/11体验)

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/modernize-packaged-apps

如果要将桌面应用更新为新式Windows 10体验,请注意,许多功能仅在具有程序包标识符的桌面应用中可用。

可通过多种方式向桌面应用授予程序包标识符:

  • 将其打包到MSIX包中。MSIX是一种新式应用包格式,提供适合所有Windows应用、WPF、Windows窗体和Win32应用的通用打包体验。它提供了可靠的安装和更新体验、功能系统灵活的托管安全模型、对MicrosoftStore的支持、企业管理以及许多自定义分发模型。有关详细信息,请参阅MSIX文档中的打包桌面应用程序
  • 如果无法采用MSIX打包来部署桌面应用,那么,自Windows10版本2004起,你可通过创建一个仅包含程序包清单的稀疏MSIX包来授予包标识。有关详细信息,请参阅向未打包的桌面应用授予标识

如果你的桌面应用具有程序包标识符,可以在其中使用以下功能:

集成包扩展

如果应用程序需要与系统集成(例如,建立防火墙规则),请在应用程序的包清单中描述集成任务,系统将完成其余操作。对于其中的大多数任务,根本不必编写任何代码。在清单中添加少量的XML后,可以执行一些操作,例如,在用户登录时启动进程、将应用程序集成到文件资源管理器中,以及为应用程序添加显示在其他应用中的打印目标列表

有关详细信息,请参阅将桌面应用与包扩展集成

获取打包应用的激活信息

从Windows 10 v1809版开始,经过打包的桌面应用可以在启动过程中检索某些类型的激活信息。例如,可以获取通过打开文件、单击交互式toast或使用协议激活应用的相关信息。

有关详细信息,请参阅获取打包应用的激活信息

使用UWP组件进行扩展

某些Windows 10体验(例如,支持触摸的UI页面)必须在新式应用容器内部运行。一般情况下,首先应确定是否可以通过Windows运行时API增强现有桌面应用程序来添加体验。如果必须使用UWP组件来实现体验,可将UWP项目添加到解决方案,并使用应用服务在桌面应用程序与UWP组件之间通信

有关详细信息,请参阅使用UWP组件扩展桌面应用

分发

如果在MSIX包中打包应用,可以通过将应用发布到Microsoft Store或将其旁加载到其他系统来分发应用。

请参阅分发打包的桌面应用

资料和示例

image

未打包的Win32应用程序的身份、注册和激活

https://blogs.windows.com/windowsdeveloper/2019/10/29/identity-registration-and-activation-of-non-packaged-win32-apps/

许多新的和受欢迎的Windows API和功能,如后台任务(BackgroundTasks)通知(Notifications)动态磁贴(LiveTiles)共享目标(Share) 等,要么无法使用,要么不容易从非打包的Win32应用程序中调用。这是由于UWP APIs的编程模型与系统集成,并对以下概念有依赖性。

  • 身份(Identity) —— 需要包或应用程序的身份来识别调用者,需要一个标识符来确定数据和资源的范围。
  • 注册(Registration) —— 在应用部署期间需要配置机器状态,这是API的要求,并由包或应用身份索引。

对于打包的应用程序,在Appxmanifest.xml中声明身份,注册由MSIX部署管道根据AppxManifest.xml中的信息处理。这使得UWP API的调用模式得到简化,应用程序代码只需使用一个API。与典型的Win32 API相比,它需要一个注册-使用-取消注册的模式来管理一个回调。

我们听到了你的反馈,作为回应,我们正在填补Win32应用程序和新的Windows API和功能之间的鸿沟,以便你可以利用这些新的API和功能,增强你的应用程序。从Windows Build 10.0.19000.0开始,我们将引入以下新的AppModel概念,为您的Win32应用程序提供与操作系统更深入的整合

  • 稀疏包(Sparse Package)注册

今天可以在Windows上安装签名的MSIX包,但包的Appxmanifest.xml中引用的所有内容必须存在于包内。一个稀疏包包含一个AppxManifest.xml,但与普通/完整包不同,清单可以在预定的 "外部位置(External Location)"引用其包以外的文件。这允许尚未能够采用完整MSIX打包的应用程序获得身份,按照UWP API的要求配置状态(注册),然后利用这些API的优势

  • 程序包外部位置(External Location)

为了支持稀疏包,包定义现在有一个新的<allowExternalContent>元素。这就是允许你的包AppxManifest.xml引用其包之外的内容,在磁盘上的一个特定位置。例如,如果你现有的Win32应用程序在C:\Program Files\MyWin32App\中安装内容,你可以创建一个稀疏包,声明<allowExternalContent>元素,在应用程序安装或首次运行时,你可以注册稀疏包并声明C:\Program Files\MyWin32App\作为你的应用程序将使用的外部位置(External Location)。这样你就可以继续在你现在的位置上部署你所有的其他应用程序工件,同时利用稀疏包的优势

  • Win32类型的RuntimeBehavior

为了帮助你现有的Win32应用程序在使用稀疏包时的兼容性,应用程序可以注册以使其应用程序尽可能地像非打包的Win32应用程序一样运行。这与完全打包的Win32应用程序不同,因为它不受文件系统+注册表虚拟化、系统的寿命管理和其他完全打包的应用程序的运行时属性的影响。这种应用程序和完全打包的应用程序之间的主要运行时相似之处是在运行进程中存在"应用程序/包(app/package)"的身份

  • 通过CreateProcess进行激活

今天UWP应用程序的激活路径确保应用程序在其进程标记中具有"包标识(PackageIdentity)"。这被UWP的API用来识别调用者,并在以后参考——要么执行回调,要么查询部署期间配置的状态。由于这个要求,在UWP exe上调用CreateProcess()将会失败,因为CreateProcess()管道没有被告知身份。为了支持具有外部位置的稀疏包,我们利用经典的Win32 application.manifest,在CreateProcess()场景中提供身份信息。

这些功能的核心是为未打包的Win32进程提供一个基础,以使用我们最新的API和功能

请注意,这些仍然是新的、有点高级的开发功能,还没有完全与Visual Studio集成,即在端到端的编写经验中仍然存在一些差距,例如必须在Visual Studio之外创建一个稀疏包

获取并体验示例程序PhotoStoreDemo

0. 前言

我们将使用一个使用稀疏包的示例应用程序来了解稀疏包编写和使用的不同方面。该演示应用程序位于https://aka.ms/sparsepkgsample

我们有一个未打包的WPF应用程序PhotoStoreDemo,用于存储和显示照片。在其纯粹的未打包状态下,利用新的Windows APIs和功能可能是一个挑战。我们的目标是通过创建一个稀疏包并继续使用我们先前已有的Win32应用程序的工件来改变这种情况

1. 什么是应用程序模型

应用程序模型(App Model) 代表了平台中的核心应用程序激活和生命周期管理基础设施。这些组件负责实际激活应用程序,创建流程,将应用程序与平台整合,管理激活-暂停-恢复-终止周期,协商资源分配,等等。应用程序模型还暴露了一些以开发者为中心的API,用于诊断。更多信息。

2. Git拉取源码

git clone https://github.com/microsoft/AppModelSamples.git

image

3. 找到PhotoStoreDemo的解决方案文件

\AppModelSamples\Samples\SparsePackages\WPF+SparsePkg.sln

image

4. 补充安装.NET Framework 4.6.1

打开WPF+SparsePkg.sln之后,会提示你有项目是通过较老版本的.NET Framework来设计的,所以这里根据提示安装。

image

装好之后,就能顺利打开项目了。

image

5. 运行并调试PhotoStoreDemo项目

我们在Visual Studio中找到PhotoStoreDemo项目并且把它设置为启动项目,启动本地调试就运行起来了。

image

image

稀疏包的剖析

一个稀疏包必须有一个AppxManifest.xml和一组最小的所需的视觉资产,以便部署。

[code lang=”xml”]

<Package
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
IgnorableNamespaces="uap10">
<Identity Name="PhotoStoreDemo" Publisher="CN=Contoso" … />
<Properties>
…
<Logo>Assets\storelogo.png</Logo>
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop"
MinVersion="10.0.19000.0"
MaxVersionTested="10.0.19000.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources"/>
</Capabilities>
…
<Applications>
<Application Id="PhotoStoreDemo"
Executable="PhotoStoreDemo.exe"
uap10:TrustLevel="mediumIL"
uap10:RuntimeBehavior="win32App">
…
</Application>
</Applications>
</Package>

[/code]

让我们使用上面示例代码中的AppxManifest.xml来看看稀疏包的结构。

包的外部位置(External Location)

首先,AppxManifest应声明<AllowExternalContent>包属性。这允许清单引用不位于包内的内容。稀疏包中引用的任何不直接位于包内的内容都应在"外部"位置,该位置在注册稀疏包时已指定。

<Properties>
    <DisplayName>PhotoStoreDemo</DisplayName>
    <PublisherDisplayName>Sparse Package</PublisherDisplayName>
    <Logo>Assets\storelogo.png</Logo>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
  </Properties>

image

例如,如果我在安装期间或第一次运行时声明我的包的外部位置是C:\Program Files\MyDesktopApp\,为<Logo>属性定义的图像storelogo.png应该安装在C:\Program Files\MyDesktopApp\Assets\storelogo.png,主要应用程序可执行文件PhotoStoreDemo.exe应该安装在C:\Program Files\MyDesktopApp\PhotoStoreDemo.exe

 <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18950.0" MaxVersionTested="10.0.19000.0" />
  </Dependencies>

image

此外,MinVersion应该是OS Build 10.0.19000.0(此处存在疑问,是否后续降低了标准?)或更高,Sparse包目前不支持早于这个版本的OS。

值得注意的是,与完全打包的应用程序不同,使用稀疏包+"外部位置(External Location)"的应用程序在部署、运行和卸载时不会被操作系统完全管理。就像现在的Win32应用程序一样,你的应用程序要负责安装和卸载它的所有工件,包括稀疏包和"外部位置(External Location)"中的任何内容。这也意味着你的应用程序不能像完全打包的应用程序那样获得终身管理和防篡改保护,因为它被安装在系统上的一个锁定位置

Win32运行时行为(Win32 Runtime Behavior)

<Application>元素中新引入的TrustLevel=mediumILRuntimeBehavior=Win32App属性被用来声明与此稀疏包相关的应用程序将像Win32应用程序一样运行,没有注册表+文件系统虚拟化和其他运行时变化

  <Applications>
    <Application Id="PhotoStoreDemo" Executable="PhotoStoreDemo.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
      <uap:VisualElements AppListEntry="none" DisplayName="PhotoStoreDemo" Description="PhotoStoreDemo" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png">
        <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png"></uap:DefaultTile>
        <uap:SplashScreen Image="Assets\SplashScreen.png" />
      </uap:VisualElements>

image

稀疏包的编写(Sparse Package Authoring)

编写稀疏包所需的步骤是。

  1. 创建一个AppxManifest.xml + 视觉资产(Visual Assets)并打包
  2. 签名稀疏包
  3. 在你的Win32应用程序中创建一个经典的Win32 application.manifest
  4. 注册稀疏包

创建和打包"AppxManifest.xml"和视觉资产(Visual Assets)

创建应用程序清单

创建一个稀疏包的第一步是生成AppxManifest.xml。AppxManifest需要包含上面列出的属性,你可以使用这个模板作为一个起点。

我们在项目跟目录下面创建一个Template文件夹,我们先按下面的模板内容创建一个名为AppxManifest.xml的应用程序清单文件。

<?xml version="1.0" encoding="utf-8"?>
<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
  IgnorableNamespaces="uap uap2 uap3 rescap desktop uap10">
  <Identity Name="PhotoStoreDemo" ProcessorArchitecture="x86" Publisher="CN=MyPubisher" Version="1.0.0.0" />
  <Properties>
    <DisplayName>Sparse Package Template</DisplayName>
    <PublisherDisplayName>My Publisher</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
  </Properties>
  <Resources>
    <Resource Language="en-us" />
  </Resources>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19000.0" MaxVersionTested="10.0.19000.0" />
  </Dependencies>
  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <rescap:Capability Name="unvirtualizedResources"/>
  </Capabilities>
  <Applications>
    <Application Id="MyApp" Executable="MyApp.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
      <uap:VisualElements DisplayName="MyApp" Description="AppDescription" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png">
        <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png"></uap:DefaultTile>
        <uap:SplashScreen Image="Assets\SplashScreen.png" />
      </uap:VisualElements>
    </Application>
  </Applications>
</Package>

image

image

这里面我们可以完善两个内容,第一个是根据自己的实际情况修改"身份(Identity)"节点的信息,比如应用名称Name,处理器架构ProcessorArchitecture,发布者信息Publisher,以及程序包版本号Version

根据需要,这里作为示范,稍作修改,改成:

<Identity Name="DemoForSparsePackage" ProcessorArchitecture="x86" Publisher="CN=Contoso Software, O=Contoso Corporation, C=US" Version="1.0.0.0" />

image

紧接着,我们看到"属性(Properties)"节点的信息,这里面有一个应用显示名称DisplayName、发布者显示名称PublisherDisplayName,这里也需要进行一些定制修改:

<Properties>
    <DisplayName>SparsePackageDemo</DisplayName>
    <PublisherDisplayName>Contoso Software</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>

另外一个,我们看到"应用(Application)"节点的信息,这里面有个一个应用标识Id和程序文件名Executable,以及程序显示名称DisplayName

这里,我们根据需要做一些修改,改成:

<Applications>
    <Application Id="Contoso.DemoForSparsePackage" Executable="DemoForSparsePackage.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
        <uap:VisualElements DisplayName="DemoForSparsePackage" Description="AppDescription" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png">
            <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png"></uap:DefaultTile>
            <uap:SplashScreen Image="Assets\SplashScreen.png" />
        </uap:VisualElements>
    </Application>
</Applications>

同时,这里其实还需要一个真正的DemoForSparsePackage.exe执行文件才行,我们弄一个过来,放在这个目录下。

image

创建应用视觉资产

除了AppxManifest之外,你还需要包括清单文件中引用的"视觉资产(Visual Assets)"。您可以使用 Visual Studio 应用程序打包项目(Application Packaging Project)package.manifest编辑器中的"视觉资产(Visual Assets)"节点来生成视觉资产。

image

弄好之后,我们在前面的Template文件夹建立一个Assets文件夹,用来存放这些素材。

image

image

通过命令打包

一旦你有了"应用清单文件(AppxManifest.xml)"和"视觉资产(Visual Assets)",你就可以使用"App Packager(MakeAppx.exe)"来创建一个稀疏包。因为稀疏包并不包含AppxManifest.xml中引用的所有文件,你需要指定/nv命令。

下面是一个从VS开发者命令提示符创建只包含AppxManifest.xml的稀疏包的命令示例。

MakeAppx.exe pack /d $AppxManifestFileDir /p $OutputMsixFilePath /nv

你可以在这里找到更多关于"App Packager(MakeAppx.exe)"的信息。

其中在Windows 11中makeappx.exe所在位置:

C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\makeappx.exe

image

那么我们先切换到它目录。

cd 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\'

然后执行命令进行打包:

.\makeappx.exe pack /d 'C:\TempSpace\HelloSparsePackage\Template\' /p 'C:\TempSpace\HelloSparsePackage\Msix\TestPackage.msix' /nv

image

好了,这时候MSIX包就生成了。

image

签署一个稀疏包

为了在一台机器上成功安装,你的Sparse包必须用该机器上信任的证书签名。这就是今天普通MSIX包的情况。你可以为开发目的创建一个新的自签名证书,并使用Windows SDK和MSIX Toolkit中的SignTool签署你的稀疏包。你还可以利用新公布的"设备保护签名(Device Guard Signing)"功能。

下面是一个如何使用"Sign工具(Sign Tool)"从VS开发者命令提示符签署稀疏包的例子。

SignTool.exe sign /fd SHA256 /a /f <path to cert>\mycert.pfx  /p <cert password>  <Path to Package>\mypackage.msix

为程序包签名创建证书

https://docs.microsoft.com/zh-cn/windows/msix/package/create-certificate-package-signing

在部署打包的应用之前,Windows对它们进行数字签名。如果不使用Microsoft Visual Studio创建应用包并签名,则需要创建和管理自己的代码签名证书。可以使用WDK驱动程序工具包中的Pvk2Pfx.exe和Windows创建(证书)。然后,可以使用证书对应用包进行签名,以便可以部署在本地进行测试。

创建和使用自签名证书时,只有安装和信任证书的用户才能运行应用程序。这很容易用于测试,但可能会阻止其他用户安装应用程序。准备好发布应用程序时,建议使用受信任源颁发的证书。这种集中式信任系统有助于确保应用程序生态系统具有验证级别,以保护用户免受恶意参与者的攻击

  1. 确定你的打包应用的主体

若要使用证书给你的应用包签名,证书中的"主体"必须匹配应用清单中的"发布者"部分

与"应用清单文件(AppxManifest.xml)"的Identity元素的Publisher属性所填的值要一一对应,等下使用的值必须是Publisher属性的完整值。

<Identity Name="Contoso.AssetTracker"
    Version="1.0.0.0"
    Publisher="CN=Contoso Software, O=Contoso Corporation, C=US"/>

那么这时候发布者身份就是:CN=Contoso Software, O=Contoso Corporation, C=US 这一整串。

  1. 使用自签名证书命令创建证书

https://docs.microsoft.com/zh-CN/powershell/module/pki/new-selfsignedcertificate

使用"自签名证书(New-SelfSignedCertificate)"命令创建证书,它包含一些自定义参数,我们这里侧重于创建一个简单的。

New-SelfSignedCertificate -Type Custom -Subject "CN=Contoso Software, O=Contoso Corporation, C=US" -KeyUsage DigitalSignature -FriendlyName "Your friendly name goes here" -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")

其中FriendlyName指代我们可以给生成的证书取一个更友好的名字,方便我们记忆,这个就随意了。

其中KeyUsage指代证书可用于什么,对于自签名证书,此参数应设置为DigitalSignature,这个参数可选的值包括:

  • CertSign
  • CRLSign
  • DataEncipherment
  • DecipherOnly
  • DigitalSignature
  • EncipherOnly
  • KeyAgreement
  • KeyEncipherment
  • None (default)
  • NonRepudiation

其中TextExtension指代可扩展的设置,其中:

  • EKU (扩展) 表示可能使用已认证的公钥的其他目的,对于自签名证书来说,这个扩展需要包括字符串:2.5.29.37={text}1.3.6.1.5.5.7.3.3,以便指示证书用于代码签名;
  • 基本约束 指示证书是否是CA证书,对于自签名证书来说,,这个扩展需要包括字符串:2.5.29.19={text},以便指示证书是最终实体(而不是CA)

其中CertStoreLocation指代证书生成后的存储位置,但是这个位置并非文件位置,而是本地证书存储库中的位置

  • 如果指定的路径是Cert:\CurrentUser或者Cert:\CurrentUser\My,那么它的默认存储位置就是Cert:\CurrentUser\My
  • 如果指定的路径是Cert:\LocalMachine或者Cert:\LocalMachine\My,那么它的默认存储位置就是Cert:\LocalMachine\My
  • 你必须指定Cert:\CurrentUser\My或者Cert:\LocalMachine\My其中一个,暂时不支持其他位置设定。

如果要查看本地存储的证书,可以通过如下命令:

Set-Location Cert:\CurrentUser\My
Get-ChildItem | Format-Table Subject, FriendlyName, Thumbprint

说完这么多,现在搞懂概念之后,我们可以打个比如了:

New-SelfSignedCertificate -Type Custom -Subject "CN=Contoso Software, O=Contoso Corporation, C=US" -KeyUsage DigitalSignature -FriendlyName "HelloSparsePackage-SelfSignedCertificate-001" -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")

image

太棒了,一气呵成!

接下来,我们可以执行查询命令看看。

Set-Location Cert:\CurrentUser\My
Get-ChildItem | Format-Table Subject, FriendlyName, Thumbprint

image

确实找到了。

如果要删除本地存储的证书,可以通过如下命令:

Remove-Item Cert:$TargetCertPath\$Thumbprint

例如:

Remove-Item Cert:\CurrentUser\My\492A496BDA7304061662DE55C533B4B657902A53
  1. 导出自签名证书

https://docs.microsoft.com/zh-cn/powershell/module/pki/export-pfxcertificate

可以通过Export-PfxCertificate命令把本地存储的证书导出到个人信息交换(PFX)文件中。

第一种是采用携带密码的方式导出,使用-Password参数。

$password = ConvertTo-SecureString -String <Your Password> -Force -AsPlainText
Export-PfxCertificate -cert "Cert:\CurrentUser\My\<Certificate Thumbprint>" -FilePath <FilePath>.pfx -Password $password

其中-cert指代待导出的本地存储证书的路径,它是由存储目录+证书指纹组成的,例如:Cert:\CurrentUser\My\0AC036CD37F5FF52B41F64F7B985E534E4E84EE0

其中-FilePath指代导出的个人信息交换(PFX)文件的位置,这里需要指定一个绝对路径,并且是带格式后缀.pfx的,例如:C:\HelloSparsePackage-SelfSignedCertificate-001.pfx

其中-Password指代导出时设定的密码,但是我们需要将其转变为安全的字符串,所以通常先在前面把它准备好。例如:$password = ConvertTo-SecureString -String "1234567" -Force -AsPlainText

综上所述,我们就可以来举个例子:

$password = ConvertTo-SecureString -String "1234567" -Force -AsPlainText
Export-PfxCertificate -cert "Cert:\CurrentUser\My\0AC036CD37F5FF52B41F64F7B985E534E4E84EE0" -FilePath 'C:\TempSpace\HelloSparsePackage\Certificate\HelloSparsePackage-SelfSignedCertificate-001.pfx' -Password $password

image

最终得到了名为HelloSparsePackage-SelfSignedCertificate-001.pfx的个人信息交换(PFX)文件。

image

第二种是采用白名单访问方式导出,使用-ProtectTo参数。

Export-PfxCertificate -cert Cert:\CurrentUser\My\<Certificate Thumbprint> -FilePath <FilePath>.pfx -ProtectTo <Username or group name>

其中-ProtectTo指代允许指定的用户名或用户组在没有密码的情况下访问这个密钥,格式采用域+用户名,例如:contoso\billb99,如果多组可以采用:-ProtectTo "contoso\billb99", "contoso\johnj99"

注意,这种方式要求具备Windows Server® 2012及其以上版本的域控制功能,所以其实对一般用户来说,无法采用这种方式。

使用SignTool对应用包进行签名

https://docs.microsoft.com/zh-cn/windows/msix/package/sign-app-package-using-signtool

SignTool是命令行工具,用于对应用包或带有证书的捆绑包进行数字签名。证书可以由用户创建(用于测试目的)或由公司颁发(用于分发)。登录应用包可验证用户登录后应用数据未经更改,并且可确认登录用户或公司的身份。SignTool可对已加密或未加密的应用包和捆绑包进行签名

  1. 确认本地安装的SignTool的路径

根据不同的系统架构版本,它的位置会存在差异,对X86和X64系统而言,他们的路径位置应该位于:

  • x86: C:\Program Files (x86)\Windows Kits\10\bin\<sdk version\x86\SignTool.exe
  • x64: C:\Program Files (x86)\Windows Kits\10\bin\<sdk version\x64\SignTool.exe

对我当前的Windows 11来说,根据这个指引找的路径是:

C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe

image

  1. 确定签名用的哈希算法

在使用SignTool对你的应用包或捆绑包进行签名时,SignTool中所用的哈希算法必须与你用于打包应用的算法相同。

对使用了MakeAppx.exe的应用包签名时,它的默认签名算法是SHA256

要找出打包应用时用到了哪种哈希算法,则需要提取应用包的内容并检查AppxBlockMap.xml文件的BlockMap元素。

查看这个信息有两种办法,一种是通过MakeAppx命令直接解压MSIX包,另外一种方法,直接用压缩软件把它解开。

MakeAppx unpack /p <input package name> /d <output directory>

例如:

cd 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\'
.\makeappx.exe unpack /p 'C:\TempSpace\HelloSparsePackage\Msix\TestPackage.msix' /d 'C:\TempSpace\HelloSparsePackage\Template-Unpack\'

image

回归正题,我们需要看看AppxBlockMap.xml文件的BlockMap元素写了什么。

<BlockMap xmlns="http://schemas.microsoft.com/appx/2010/blockmap" xmlns:b4="http://schemas.microsoft.com/appx/2021/blockmap" IgnorableNamespaces="b4" HashMethod="http://www.w3.org/2001/04/xmlenc#sha256">...

我们看到这里有个"哈希方法(HashMethod)",它的值是http://www.w3.org/2001/04/xmlenc#sha256,那么它和我们要确认的哈希算法之间的关系是:

HashMethod 值 哈希算法
http://www.w3.org/2001/04/xmlenc#sha256 SHA256
http://www.w3.org/2001/04/xmldsig-more#sha384 SHA384
http://www.w3.org/2001/04/xmlenc#sha512 SHA512

所以这里我们能确认的是,当前MSIX包采用的打包哈希算法就是SHA256

通过命令对MSIX包签名

https://docs.microsoft.com/zh-CN/windows/win32/seccrypto/signtool

如果我们要基于个人信息交换(PFX)文件进行签名,那么可以采用:

SignTool sign /fd <Hash Algorithm> /a /f <Path to Certificate>.pfx /p <Your Password> <File path>.msix

其中/fd指代签名是采用何种哈希算法,其完整示例比如:/fd SHA256

其中/a指代让工具自动选择最合适的证书进行签名。

其中/f指代个人信息交换(PFX)文件的路径,而/p指代它的访问密码,其完整示例比如:/f 'C:\H.pfx' /p '123457'

其中<File path>.msix指代了待被签名的MSIX包的完整路径,例如:C:\demo.msix

甚至我们还可以加盖时间戳,使用参数:/t http://timestamp.digicert.com,但是这个会增加签名的时间哈。

综上所述,我们就可以来举个例子:

cd 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\'
.\signtool.exe sign /fd SHA256 /a /f 'C:\TempSpace\HelloSparsePackage\Certificate\HelloSparsePackage-SelfSignedCertificate-001.pfx' /t 'http://timestamp.digicert.com' /p '1234567' 'C:\TempSpace\HelloSparsePackage\Msix\TestPackage.msix'
.\signtool.exe sign /fd SHA256 /a /f 'C:\TempSpace\HelloSparsePackage\Certificate\HelloSparsePackage-SelfSignedCertificate-001.pfx' /p '1234567' 'C:\TempSpace\HelloSparsePackage\Msix\TestPackage.msix'
Done Adding Additional Store
Successfully signed: C:\TempSpace\HelloSparsePackage\Msix\TestPackage.msix

image

我们需要注意这前后的变化,在之前,这个MSIX是没有签名的:

image

完成这一步之后,它有数字签名了:

image

创建一个经典的Win32程序配置

https://docs.microsoft.com/zh-cn/windows/win32/sbscs/application-manifests

为了支持不经过UWP激活管道的CreateProcess()方案,您的应用程序必须使用经典的Win32风格的application.manifest,在新的<msix>元素下声明您的应用程序的身份属性。在清单中定义的值在其可执行程序启动时用于确定您的应用程序的身份,并且必须与您的稀疏包的AppxManifest.xml中声明的值一致

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
    <assemblyIdentity version="0.0.0.1" name="PhotoStoreDemo.app"/>
    <msix xmlns="urn:schemas-microsoft-com:msix.v1"
        publisher="CN=Contoso"
        packageName="PhotoStoreDemo"
        applicationId="PhotoStoreDemo"
        />
</assembly>

packageName(上面)对应于Namepublisher对应于Sparse包的<Identity>元素中的Publisher

<Identity Name="PhotoStoreDemo" Publisher="CN=Contoso" … />

applicationId对应于在Sparse包中声明的这个应用程序的<Application>元素的Id属性。

Applications>
<Application Id="PhotoStoreDemo"…>
…

要在Visual studio中向现有项目添加经典的Win32清单,可在应用程序节点中右键单击|添加|新项目|Visual C#|应用程序清单文件。清单文件的命名惯例是,它必须与您的应用程序的.exe名称相同,并具有.manifest扩展名,在本例中我将其命名为 "PhotoStoreDemo.exe.manifest"。

这里需要注意的是,这个应用程序清单的.Msix元素,只有在Windows 10 v2004及其以上版本才能识别并支持。

其中msix元素必须在urn:schemas-microsoft-com:msix.v1的命名空间中。

属性 说明
publisher 介绍发布服务器信息。此值必须与稀疏包清单中的Identity元素中的Publisher特性匹配。
packageName 描述包的内容。此值必须与稀疏包清单中的Identity元素的Name特性匹配。
applicationId 应用程序的唯一标识符。此值必须与稀疏包清单中的应用程序Application元素的Id特性匹配。

添加应用程序清单

在项目上右键"添加"-"新建项"。

image

进入"添加新项"对话框,找到"应用程序清单(仅限Windows)"。

image

这里命名必须和应用程序的程序集带后缀名称一致,比如:DemoForSparseWPF.exe.manifest

image

生成后项目属性里面的清单会自动关联到它。

image

不过从默认得到的模板来看,里面还是蛮复杂的,为很多场景做了举例。

image

定制稀疏包的清单内容

有了应用程序清单文件,我们就可以定制添加需要的清单内容了,先打个草稿,这里我们需要和稀疏包的清单文件保持一致,所以确定下来的内容是:

<msix xmlns="urn:schemas-microsoft-com:msix.v1"
    publisher="CN=Contoso Software, O=Contoso Corporation, C=US"
    packageName="DemoForSparsePackage"
    applicationId="Contoso.DemoForSparsePackage"
    />

另外清单文件里面,还有个assemblyIdentity元素的名称name,也一起改吧,这个根据对应的程序名称来就行。

我们把这个msix补充在清单文件的assemblyIdentity节点后面。

image

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="DemoForSparseWPF.App"/>
  <msix xmlns="urn:schemas-microsoft-com:msix.v1"
    publisher="CN=Contoso Software, O=Contoso Corporation, C=US"
    packageName="DemoForSparsePackage"
    applicationId="Contoso.DemoForSparsePackage"
    />
...

利用你的应用程序的稀疏包的优势

如前所述,为你的应用程序创建一个稀疏包使你的Win32应用程序更容易与操作系统深度集成,并利用诸如BackgroundTasks、共享、通知和瓷砖等功能。让我们来看看我们的样本应用程序是如何运行和使用稀疏包来注册为一个共享目标并利用UWP激活的。

我们的样本中的工作流程看起来是这样的:

  1. 在稀疏包AppxManifest.xml声明我们的应用程序是一个共享目标
  2. 向操作系统注册我们的应用程序的稀疏包
  3. 重新启动应用程序并处理激活类型

使用实例 - 在稀疏包AppxManifest.xml中声明你的应用程序是一个共享目标。

我们的示例应用程序通过在稀疏包AppxManifest.xml中声明windows.ShareTarget应用程序扩展来注册为一个共享目标

<Extensions>
    <uap:Extension Category="windows.shareTarget">
        <uap:ShareTarget Description="Send to PhotoStoreDemo">
            <uap:SupportedFileTypes>
                <uap:FileType>.jpg</uap:FileType>
                <uap:FileType>.png</uap:FileType>
                <uap:FileType>.gif</uap:FileType>
            </uap:SupportedFileTypes>
            <uap:DataFormat>StorageItems</uap:DataFormat>
            <uap:DataFormat>Bitmap</uap:DataFormat>
        </uap:ShareTarget>
    </uap:Extension>
</Extensions>

所以这个AppxManifest.xml文件我们修改成:

	...
	</Applications>
	<Extensions>
		<uap:Extension Category="windows.shareTarget">
			<uap:ShareTarget Description="发送到SparsePackageDemo">
				<uap:SupportedFileTypes>
					<uap:FileType>.jpg</uap:FileType>
					<uap:FileType>.png</uap:FileType>
					<uap:FileType>.gif</uap:FileType>
				</uap:SupportedFileTypes>
				<uap:DataFormat>StorageItems</uap:DataFormat>
				<uap:DataFormat>Bitmap</uap:DataFormat>
			</uap:ShareTarget>
		</uap:Extension>
	</Extensions>
</Package>

image

注册一个稀疏包

为了利用稀疏包,你的应用程序需要在系统中注册签名的包。你可以在第一次运行时注册该包,或者你也可以在安装其他Win32工件时注册该包,如果你使用MSI这样的安装程序。要使用MSI安装软件包,你需要使用自定义动作。在我们的示例应用程序中,我们在第一次运行时注册稀疏包。当我们的应用程序被启动时,我们检查它是否以身份信息运行(身份信息或没有身份信息是稀疏包是否被注册/安装的信号)如果应用程序没有以身份信息运行,我们就注册稀疏包并重新启动应用程序。这预计只在首次运行时发生一次。要看我们如何确定应用程序是否以身份运行,如果你想了解更多背景,请看ExecutionMode类和这篇帖子。

这就是我们应用程序中的代码的样子:

//if app isn’t running with identity, register its sparse package
if (!ExecutionMode.IsRunningWithIdentity())
{
    string externalLocation = @"C:\<App_Install_location_root>\";
    string sparsePkgPath = @"C:\<App_Install_location_root>\PhotoStoreDemo.msix";

    //Attempt registration
    if (registerSparsePackage(externalLocation, sparsePkgPath))
    {
        //Registration succeded, restart the app to run with identity
        System.Diagnostics.Process.Start(Application.ResourceAssembly.Location, arguments: cmdArgs?.ToString());
    }
    else //Registration failed, run without identity
    {
        Debug.WriteLine("Package Registation failed, running WITHOUT Identity");
        SingleInstanceManager wrapper = new SingleInstanceManager();
        wrapper.Run(cmdArgs);
    }
}

而这是上面调用的处理包注册的registerSparsePackage方法:

Using Windows.Management.Deployment
…
private static bool registerSparsePackage(string externalLocation, string sparsePkgPath)
{
    bool registration = false;
    try
    {
        Uri externalUri = new Uri(externalLocation);
        Uri packageUri = new Uri(sparsePkgPath);
        PackageManager packageManager = new PackageManager();
        //Set the externalLocation where your Win32 artifacts will be installed
        //Anything not in the package but referenced by your AppxManifest.xml needs to to be under this location
        var options = new AddPackageOptions();
        options.ExternalLocationUri = externalUri;

        Windows.Foundation.IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> deploymentOperation = packageManager.AddPackageByUriAsync(packageUri, options)

为了注册稀疏包,你需要使用PackageManager AddPackageByUriAsync(packageUri, addPackageOptions)API。该API接收你签名的稀疏包的位置作为URI和一个AddPackageOptions对象。你需要创建一个AddpackageOptions对象,并将ExternalLocationUri属性设置为URI,即在稀疏包中被引用的Win32工件(如应用程序可执行文件)将被安装的位置。

处理应用程序的激活

生成并注册稀疏包

为稀疏包创建程序包清单

生成稀疏包并为稀疏包签名

将程序包标识符元数据添加到桌面应用程序清单

在运行时注册稀疏包

使用打包扩展将桌面应用与Windows集成

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/desktop-to-uwp-extensions

如果桌面应用具有程序包标识符,你可通过程序包清单中的预定义扩展,使用扩展将应用与Windows 10及更高版本进行集成。

例如,使用扩展创建一个防火墙例外,使应用成为某一文件类型的默认应用程序,或将“开始”磁贴指向你的应用。若要使用扩展,只需将某些XML添加到应用的程序包清单文件。不需要任何代码。

获取打包应用的激活信息

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/get-activation-info-for-packaged-apps

从Windows 10 v1809版开始,经过打包的桌面应用可以调用AppInstance.GetActivatedEventArgs方法,在启动过程中检索某些类型的应用激活信息。例如,可以调用此方法获取通过打开文件、单击交互式toast或使用协议激活应用的相关信息。从Windows 10 v2004版开始,使用稀疏包的应用中也支持此功能

代码示例

下面的代码示例演示如何通过Windows窗体应用中的Main函数调用AppInstance.GetActivatedEventArgs方法。对于应用支持的每个激活类型,将args返回值强制转换为相应的事件args类型。此代码示例假定Handlexxx方法是在其他地方定义的专用激活处理程序代码。

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    var args = AppInstance.GetActivatedEventArgs();
    switch (args.Kind)
    {
        case ActivationKind.Launch:
            HandleLaunch(args as LaunchActivatedEventArgs);
            break;
        case ActivationKind.ToastNotification:
            HandleToastNotification(args as ToastNotificationActivatedEventArgs);
            break;
        case ActivationKind.VoiceCommand:
            HandleVoiceCommand(args as VoiceCommandActivatedEventArgs);
            break;
        case ActivationKind.File:
            HandleFile(args as FileActivatedEventArgs);
            break;
        case ActivationKind.Protocol:
            HandleProtocol(args as ProtocolActivatedEventArgs);
            break;
        case ActivationKind.StartupTask:
            HandleStartupTask(args as StartupTaskActivatedEventArgs);
            break;
        default:
            HandleLaunch(null);
            break;
    }

支持的激活类型

可以使用AppInstance.GetActivatedEventArgs方法从下表中列出的一组受支持的事件args对象中检索激活信息。其中一些激活类型要求使用程序包清单中的一个程序包扩展。

仅Windows 10 v2004版及更高版本支持ShareTargetActivatedEventArgs激活信息。Windows 10 v1809版及更高版本支持所有其他激活信息类型。

事件args类型 程序包扩展 相关文档
ShareTargetActivatedEventArgs uap:ShareTarget 使桌面应用程序成为共享目标
ProtocolActivatedEventArgs uap:Protocol 使用协议启动应用程序
ToastNotificationActivatedEventArgs desktop:ToastNotificationActivation 来自桌面应用的Toast通知。
StartupTaskActivatedEventArgs desktop:StartupTask 用户登录Windows时启动可执行文件
FileActivatedEventArgs uap:FileTypeAssociation 将打包的应用程序与一组文件类型相关联
VoiceCommandActivatedEventArgs 处理激活和执行语音命令
LaunchActivatedEventArgs

使用新式UWP组件扩展桌面应用

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/desktop-to-uwp-extend

某些Windows 10体验(例如,支持触摸的UI页面)必须在新式应用容器内部运行。如果要添加这些体验,请用UWP项目和Windows运行时组件扩展桌面应用程序。

在许多情况下,你可以直接从桌面应用程序中调用Windows运行时API,因此在查看本指南前,请参阅面向Windows 10的增强

本文中所述的功能要求桌面应用具有程序包标识符(通过在MSIX包中打包桌面应用或使用稀疏包授予应用标识)

如果你准备好了,那我们就开始吧。

在桌面应用中调用Windows运行时API

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/desktop-to-uwp-enhance

桌面应用项目以使用WindowsOS提供的Windows运行时(WinRT)API,并将新式Windows11和Windows10体验添加到桌面应用。

桌面应用中不支持某些Windows运行时(WinRT)API。有关详细信息,请参阅桌面应用中不支持的Windows运行时API。

修改.NET项目以使用Windows运行时API

有几个用于.NET项目的选项:

  • 从.NET5开始,可以在项目文件中添加目标框架名字对象(TFM),用于访问WinRTAPI。此选项支持面向Windows 10 v1809版或更高版本的项目。
  • 对于早期版本的.NET,可以安装Microsoft.Windows.SDK.Contracts的NuGet包,以便将所有必要的引用添加到项目中。此选项支持面向Windows 10 v1803版或更高版本的项目。
  • 如果你的项目同时面向.NET5(或更高版本)和早期版本的.NET等多个目标,可将项目文件配置为同时使用这两个选项。

实践

https://github.com/TaylorShi/HelloSparsePackage

创建解决方案HelloSparsePackage

dotnet new sln -o HelloSparsePackage

image

cd .\HelloSparsePackage\

image

explorer.exe .

image

创建Windows应用程序打包项目DemoForSparsePacking

在Visual Studio中,在解决方案HelloSparsePackage上右键选择"添加"->"新建项目",打开新建项目对话框。

image

语言项选"所有语言",平台项选"Windows",项目类型项选"桌面",往下拉,找到"Windows应用程序打包项目",点击"下一步"。

image

输入新项目名DemoForSparsePacking,然后点击"创建"按钮即可完成项目创建。

image

在"新式通用Windows平台项目",这里我们就保持默认,目标版本和最低版本都按推荐值来吧,最后点击"确定"即可。

image

接下来,Windows应用程序打包项目DemoForSparsePacking就创建好了。

image

创建.Net Framework的Winforms项目DemoForSparseWinforms

在Visual Studio中,在解决方案HelloSparsePackage上右键选择"添加"->"新建项目",打开新建项目对话框。

image

语言项选"C#",平台项选"Windows",项目类型项选"桌面",往下拉,找到"Windows窗体应用(.Net Framework)",点击"下一步"。

image

输入新项目名DemoForSparseWinforms,框架项选择".Net framework 2.0",然后点击"创建"按钮即可完成项目创建。

image

接下来,Windows窗体应用(.Net Framework)项目DemoForSparseWinforms就创建好了。

image

创建.Net Framework的WPF项目DemoForSparseWPF

在Visual Studio中,在解决方案HelloSparsePackage上右键选择"添加"->"新建项目",打开新建项目对话框。

image

语言项选"C#",平台项选"Windows",项目类型项选"桌面",往下拉,找到"WPF应用(.Net Framework)",点击"下一步"。

image

输入新项目名DemoForSparseWPF,框架项选择".Net framework 4.6.1",然后点击"创建"按钮即可完成项目创建。

image

接下来,WPF应用(.Net Framework)项目DemoForSparseWPF就创建好了。

image

案例分析:WinRAR

新闻

2022年1月25日,老牌压缩软件WinRAR迎来了6.10正式版更新,更新提供了对Windows 11右键菜单的支持。

image

安装

目录

image

我们看到安装目录下面有个RarExtPackage.msix,接下来打开看看它。

解剖

RarExtPackage.msix解开,里面一些文件。

image

右边就是一些视觉资产文件,它这个比较简单了,只包括:

  • RarExtLogo.altform-unplated_targetsize-32.png
  • RarExtLogo.altform-unplated_targetsize-48.png
  • RarExtLogo.altform-unplated_targetsize-64.png
  • Square150x150Logo.png
  • StoreLogo.png

基本上也够用了。反映到AppxManifest.xml中来看呢,对应了

<Properties>
    <DisplayName>WinRAR</DisplayName>
    <PublisherDisplayName>win.rar GmbH</PublisherDisplayName>
    <Logo>StoreLogo.png</Logo>
    <desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
    <desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Applications>
    <Application Id="WinRAR.ShellExtension" Executable="RarExtInstaller.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
        <uap:VisualElements AppListEntry="none" DisplayName="WinRAR" Description="RarExtInstaller.exe" BackgroundColor="transparent" Square150x150Logo="Square150x150Logo.png" Square44x44Logo="RarExtLogo.png">
        </uap:VisualElements>
    </Application>
</Applications>

左边是MSIX要求的一些描述文件了,其中AppxManifest.xml整体的看一下:

<?xml version="1.0" encoding="utf-8"?>
<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
  xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
  xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
  xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 uap10 com">
  <Identity Name="WinRAR.ShellExtension" Publisher="CN=win.rar GmbH, O=win.rar GmbH, L=Berlin, S=Berlin, C=DE" ProcessorArchitecture="x64" Version="1.0.0.1" />
  <Properties>
    <DisplayName>WinRAR</DisplayName>
    <PublisherDisplayName>win.rar GmbH</PublisherDisplayName>
    <Logo>StoreLogo.png</Logo>
    <desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
    <desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
  </Properties>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
  </Dependencies>
  <Resources>
    <Resource Language="EN-US" />
  </Resources>
  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <rescap:Capability Name="unvirtualizedResources"/>
  </Capabilities>
  <Applications>
    <Application Id="WinRAR.ShellExtension" Executable="RarExtInstaller.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
      <uap:VisualElements AppListEntry="none" DisplayName="WinRAR" Description="RarExtInstaller.exe" BackgroundColor="transparent" Square150x150Logo="Square150x150Logo.png" Square44x44Logo="RarExtLogo.png">
      </uap:VisualElements>
      <Extensions>
        <com:Extension Category="windows.comServer">
          <com:ComServer>
            <com:SurrogateServer DisplayName="WinRAR">
              <com:Class Id="b41db860-64e4-11d2-9906-e49fadc173ca" Path="RarExt.dll" ThreadingModel="STA" />
            </com:SurrogateServer>
          </com:ComServer>
        </com:Extension>
        <desktop4:Extension Category="windows.fileExplorerContextMenus">
          <desktop4:FileExplorerContextMenus>
            <desktop5:ItemType Type="*">
              <desktop5:Verb Id="WinRARTopEntry" Clsid="b41db860-64e4-11d2-9906-e49fadc173ca" />
            </desktop5:ItemType>
            <desktop5:ItemType Type="Directory">
              <desktop5:Verb Id="WinRARTopEntry" Clsid="b41db860-64e4-11d2-9906-e49fadc173ca" />
            </desktop5:ItemType>
          </desktop4:FileExplorerContextMenus>
        </desktop4:Extension>
      </Extensions>
    </Application>
  </Applications>
</Package>

至于[Content_Types].xmlAppxBlockMap.xml我暂时觉得就没必要看了,应该是创建MSIX包自动生成的。

案例分析:NanaZip

新闻

2021年10月31日,NanaZip基于7-Zip,因此功能和性能都和7-Zip差不多,甚至连界面也和7-Zip一个简陋风格,除了提供最基础的交互,没有什么精美的设计。

image

image

功能

  • 继承了7-Zip 21.07的所有功能。
  • 使用MSIX打包,以获得现代部署体验
  • 支持Windows 10/11文件管理器中的上下文菜单
  • 启用NSIS档案的NSIS脚本反编译支持。(合并自7-Zip NSIS分支。)
  • 提供7-Zip执行别名,帮助用户迁移到NanaZip。
  • 支持 Brotli,Fast-LZMA2,Lizard, LZ4, LZ5和Zstandard编解码器。(合并自7-Zip ZS分支。)

安装

a. 从微软官方商店获取

NanaZip是一个开放源码的文件存档器,旨在为现代的Windows体验,从著名的开放源码文件存档器7-Zip的源代码分叉出来。

b. 从Github发布页获取

目录

image

这是一个MSIX打包的应用。

解剖

其中AppxManifest.xml整体的看一下:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Package IgnorableNamespaces="uap rescap desktop uap3 com desktop4 desktop5 uap8 virtualization build" xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4" xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5" xmlns:uap8="http://schemas.microsoft.com/appx/manifest/uap/windows10/8" xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10" xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest">
  <Identity Name="40174MouriNaruto.NanaZipPreview" Publisher="CN=E310A153-74A9-4D81-800B-857A8D58408A" Version="1.1.153.0" ProcessorArchitecture="x64" />
  <Properties>
    <DisplayName>NanaZip Preview</DisplayName>
    <PublisherDisplayName>Kenji Mouri</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
    <virtualization:FileSystemWriteVirtualization>
      <virtualization:ExcludedDirectories>
        <virtualization:ExcludedDirectory>$(KnownFolder:LocalAppData)</virtualization:ExcludedDirectory>
        <virtualization:ExcludedDirectory>$(KnownFolder:LocalAppDataLow)</virtualization:ExcludedDirectory>
        <virtualization:ExcludedDirectory>$(KnownFolder:RoamingAppData)</virtualization:ExcludedDirectory>
      </virtualization:ExcludedDirectories>
    </virtualization:FileSystemWriteVirtualization>
  </Properties>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22000.0" />
  </Dependencies>
  <Resources>
    <Resource Language="EN-US" />
    <Resource uap:Scale="100" />
    <Resource uap:Scale="200" />
    <Resource uap:Scale="400" />
  </Resources>
  <Applications>
    <Application Id="NanaZipC" Executable="NanaZip.exe" EntryPoint="Windows.FullTrustApplication">
      <uap:VisualElements AppListEntry="none" DisplayName="NanaZip Preview" Description="NanaZip" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" />
      <Extensions>
        <uap3:Extension Category="windows.appExecutionAlias" Executable="NanaZipC.exe" EntryPoint="Windows.FullTrustApplication">
          <uap3:AppExecutionAlias>
            <desktop:ExecutionAlias Alias="NanaZipC.exe" />
            <desktop:ExecutionAlias Alias="7z.exe" uap8:AllowOverride="true" />
          </uap3:AppExecutionAlias>
        </uap3:Extension>
      </Extensions>
    </Application>
    <Application Id="NanaZipG" Executable="NanaZipG.exe" EntryPoint="Windows.FullTrustApplication">
      <uap:VisualElements AppListEntry="none" DisplayName="NanaZip Preview" Description="NanaZip" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" />
      <Extensions>
        <uap3:Extension Category="windows.appExecutionAlias" Executable="NanaZipG.exe" EntryPoint="Windows.FullTrustApplication">
          <uap3:AppExecutionAlias>
            <desktop:ExecutionAlias Alias="NanaZipG.exe" />
            <desktop:ExecutionAlias Alias="7zG.exe" uap8:AllowOverride="true" />
          </uap3:AppExecutionAlias>
        </uap3:Extension>
      </Extensions>
    </Application>
    <Application Id="NanaZip" Executable="NanaZip.exe" EntryPoint="Windows.FullTrustApplication">
      <uap:VisualElements DisplayName="NanaZip Preview" Description="NanaZip" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png">
        <uap:DefaultTile ShortName="NanaZip" Wide310x150Logo="Assets\Wide310x150Logo.png" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png">
          <uap:ShowNameOnTiles>
            <uap:ShowOn Tile="wide310x150Logo" />
            <uap:ShowOn Tile="square150x150Logo" />
            <uap:ShowOn Tile="square310x310Logo" />
          </uap:ShowNameOnTiles>
        </uap:DefaultTile>
      </uap:VisualElements>
      <Extensions>
        <uap3:Extension Category="windows.appExecutionAlias" Executable="NanaZip.exe" EntryPoint="Windows.FullTrustApplication">
          <uap3:AppExecutionAlias>
            <desktop:ExecutionAlias Alias="NanaZip.exe" />
            <desktop:ExecutionAlias Alias="7zFM.exe" uap8:AllowOverride="true" />
          </uap3:AppExecutionAlias>
        </uap3:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_001">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - 001 Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.001</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_7z">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - 7z Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.7z</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_arj">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - arj Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.arj</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_bz2">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - bz2 Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.bz2</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_bzip2">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - bzip2 Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.bzip2</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_cab">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - cab Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.cab</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_cpio">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - cpio Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.cpio</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_deb">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - deb Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.deb</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_dmg">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - dmg Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.dmg</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_esd">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - esd Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.esd</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_fat">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - fat Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.fat</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_gz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - gz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.gz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_gzip">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - gzip Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.gzip</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_hfs">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - hfs Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.hfs</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_iso">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - iso Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.iso</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_lha">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - lha Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.lha</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_liz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - liz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.liz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_lz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - lz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.lz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_lz4">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - lz4 Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.lz4</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_lz5">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - lz5 Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.lz5</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_lzh">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - lzh Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.lzh</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_lzma">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - lzma Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.lzma</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_ntfs">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - ntfs Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.ntfs</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_rar">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - rar Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.rar</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_rpm">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - rpm Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.rpm</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_squashfs">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - squashfs Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.squashfs</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_swm">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - swm Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.swm</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_tar">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - tar Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.tar</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_taz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - taz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.taz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_tbz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - tbz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.tbz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_tbz2">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - tbz2 Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.tbz2</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_tgz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - tgz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.tgz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_tlz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - tlz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.tlz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_tpz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - tpz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.tpz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_txz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - txz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.txz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_vhd">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - vhd Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.vhd</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_vhdx">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - vhdx Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.vhdx</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_wim">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - wim Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.wim</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_xar">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - xar Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.xar</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_xz">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - xz Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.xz</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_z">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - z Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.z</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_zip">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - zip Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.zip</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <uap:Extension Category="windows.fileTypeAssociation">
          <uap:FileTypeAssociation Name="archivetype_zst">
            <uap:Logo>Assets\ArchiveFile.png</uap:Logo>
            <uap:DisplayName>NanaZip - zst Archive</uap:DisplayName>
            <uap:SupportedFileTypes>
              <uap:FileType>.zst</uap:FileType>
            </uap:SupportedFileTypes>
          </uap:FileTypeAssociation>
        </uap:Extension>
        <desktop4:Extension Category="windows.fileExplorerContextMenus">
          <desktop4:FileExplorerContextMenus>
            <desktop5:ItemType Type="Directory">
              <desktop5:Verb Id="NanaZipShellExtension" Clsid="469D94E9-6AF4-4395-B396-99B1308F8CE5" />
            </desktop5:ItemType>
            <desktop5:ItemType Type="*">
              <desktop5:Verb Id="NanaZipShellExtension" Clsid="469D94E9-6AF4-4395-B396-99B1308F8CE5" />
            </desktop5:ItemType>
          </desktop4:FileExplorerContextMenus>
        </desktop4:Extension>
        <com:Extension Category="windows.comServer">
          <com:ComServer>
            <com:SurrogateServer DisplayName="NanaZip Shell Extension">
              <com:Class Id="469D94E9-6AF4-4395-B396-99B1308F8CE5" Path="NanaZipShellExtension.dll" ThreadingModel="STA" />
            </com:SurrogateServer>
          </com:ComServer>
        </com:Extension>
      </Extensions>
    </Application>
  </Applications>
  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
  </Capabilities>
  <build:Metadata>
    <build:Item Name="Microsoft.Build.DesktopBridge.Tasks.dll" Version="4.6.30319.200" />
    <build:Item Name="TargetFrameworkMoniker" Value="native,Version=v0.0" />
    <build:Item Name="VisualStudio" Version="17.0" />
    <build:Item Name="OperatingSystem" Version="10.0.22000.434 (WinBuild.160101.0800)" />
    <build:Item Name="Microsoft.Build.AppxPackage.dll" Version="17.0.31912.81" />
    <build:Item Name="ProjectGUID" Value="9a119a76-97cb-4490-b8c2-651576cb9302" />
    <build:Item Name="MakePri.exe" Version="10.0.22000.194 (WinBuild.160101.0800)" />
  </build:Metadata>
  <mp:PhoneIdentity PhoneProductId="0f6c8cd6-bec0-499c-810f-28e88a3e4b62" PhonePublisherId="5865126c-fd0a-473f-9c00-925aa3a04529" />
</Package>

参考

posted @ 2022-01-18 17:06  TaylorShi  阅读(1512)  评论(3编辑  收藏  举报