Предоставление удостоверения пакета путем упаковки с внешним расположением

Если у вас есть классическое приложение с собственным установщиком, вам мало нужно изменить, чтобы воспользоваться удостоверением пакета.

Многие функции расширения Windows, включая фоновые задачи, уведомления, динамические плитки, пользовательские расширения контекстного меню и целевые объекты общего доступа, могут использоваться классическим приложением только в том случае, если это приложение имеет удостоверение пакета во время выполнения. Это связано с тем, что операционная система (ОС) должна иметь возможность идентифицировать вызывающий объект соответствующего API. См. сведения о функциях, требующих удостоверения пакета.

Только упакованные приложения имеют удостоверение пакета во время выполнения. Определения приложений, которые упаковываются, распаковываются и упаковываются с внешним расположением, см. в обзоре развертывания.

  • В Windows 10 версии 2004 и ранее единственным способом предоставить удостоверение пакета приложению — упаковать его в подписанный пакет MSIX (см. статью "Создание пакета MSIX из кода"). В этом случае удостоверение указывается в манифесте пакета, а регистрация удостоверений обрабатывается конвейером развертывания MSIX на основе сведений в манифесте. Все содержимое, на которое ссылается манифест пакета, содержится в пакете MSIX.
  • Но начиная с Windows 10 версии 2004, вы можете предоставить удостоверение пакета приложению, просто создав и зарегистрируя пакет с внешним расположением в приложении. Это превращает его в упакованое приложение; в частности, упакованое приложение с внешним расположением. Это связано с тем, что некоторые классические приложения еще не готовы ко всем их содержимому, которые будут присутствовать в пакете MSIX. Таким образом, эта поддержка позволяет таким приложениям иметь удостоверение пакета; Таким образом, возможность использовать функции расширения Windows, требующие удостоверения пакета. Дополнительные сведения см. в записи блога Identity, Registration and Activation of Non packaged Win32 Apps.

Чтобы создать и зарегистрировать пакет с внешним расположением (которое предоставляет удостоверение пакета приложению), выполните следующие действия.

  1. Создание манифеста пакета для пакета с внешним расположением
  2. Создание и подписание пакета с внешним расположением
  3. Добавьте метаданные идентификатора пакета в манифест классического приложения.
  4. Регистрация пакета с внешним расположением во время выполнения

Важные понятия

Следующие функции позволяют распаковывать классические приложения для получения удостоверения пакета.

Упаковка с внешним расположением

Пакет с внешним расположением содержит манифест пакета, но никакие другие двоичные файлы и содержимое приложения. Манифест пакета с внешним расположением может ссылаться на файлы за пределами пакета в предопределенном внешнем расположении. Как упоминание выше, эта поддержка позволяет приложениям, которые еще не готовы к тому, чтобы все их содержимое присутствовало в пакете MSIX для использования функций расширяемости Windows, требующих удостоверения пакета.

Примечание.

Классическое приложение, использующее пакет с внешним расположением, не получает некоторые преимущества полного развертывания с помощью пакета MSIX. К таким преимуществам относятся защита от подделки, установка в заблокированном расположении и полное управление ОС во время развертывания, выполнения и удаления.

Разрешение внешнего содержимого

Для поддержки пакетов с внешним расположением схема манифеста пакета теперь поддерживает необязательный элемент uap10:AllowExternalContent в элементе Properties . Это позволяет манифесту пакета ссылаться на содержимое за пределами пакета в определенном расположении на диске.

Например, если у вас есть существующее непакованное классическое приложение, которое устанавливает исполняемый файл приложения и другое содержимое в C:\Program Files\MyDesktopApp, можно создать пакет с внешним расположением, которое включает элемент uap10:AllowExternalContent в манифесте. Во время установки приложения или при первом запуске приложения можно установить пакет с внешним расположением и объявить C:\Program Files\MyDesktopApp\ в качестве внешнего расположения, которое будет использоваться приложением.

Создание манифеста пакета для пакета с внешним расположением

Прежде чем создать пакет с внешним расположением, необходимо сначала создать манифест пакета (файл с именем AppxManifest.xml), который объявляет метаданные удостоверения пакета для классического приложения и другие необходимые сведения. Самый простой способ создать манифест пакета для пакета с внешним расположением — использовать приведенный ниже пример и настроить его для приложения с помощью ссылки на схему.

Убедитесь, что манифест пакета содержит следующие элементы:

  • Элемент Identity, описывающий атрибуты идентификатора для классического приложения.
  • Элемент uap10:AllowExternalContent в элементе Properties. Этому элементу следует присвоить значение true, что позволяет манифесту пакета ссылаться на содержимое вне пакета в определенном расположении на диске. На следующем шаге вы укажете путь к внешнему расположению при регистрации пакета с внешним расположением из кода, работающего в установщике или приложении. Любое содержимое, на которое вы ссылаетесь в манифесте и которое не находится в самом пакете, должно быть установлено во внешнем расположении.
  • Для атрибута MinVersion элемента TargetDeviceFamily следует задать 10.0.19000.0 или более позднюю версию.
  • Атрибуты TrustLevel=mediumIL и RuntimeBehavior=Win32App элемента Application объявляют, что классическое приложение, связанное с пакетом с внешним расположением, будет выполняться аналогично стандартному классическому приложению без виртуализации реестра и файловой системы и других изменений времени выполнения.

В следующем примере показано полное содержимое пакета с манифестом внешнего расположения (AppxManifest.xml). Этот манифест содержит расширение windows.sharetarget, для которого требуется идентификатор пакета.

<?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="ContosoPhotoStore" ProcessorArchitecture="x64" Publisher="CN=Contoso" Version="1.0.0.0" />
  <Properties>
    <DisplayName>ContosoPhotoStore</DisplayName>
    <PublisherDisplayName>Contoso</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="ContosoPhotoStore" Executable="ContosoPhotoStore.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App"> 
      <uap:VisualElements AppListEntry="none" DisplayName="Contoso PhotoStore" Description="Demonstrate photo app" 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>
      <Extensions>
        <uap:Extension Category="windows.shareTarget">
          <uap:ShareTarget Description="Send to ContosoPhotoStore">
            <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>
    </Application>
  </Applications>
</Package>

Создание и подписание пакета с внешним расположением

После создания манифеста пакета создайте пакет с внешним расположением с помощью средства MakeAppx.exe в пакете SDK для Windows. Так как пакет с внешним расположением не содержит файлы, на которые ссылается манифест, необходимо указать /nv параметр, который пропускает семантику проверки пакета.

В следующем примере показано, как создать пакет с внешним расположением из командной строки.

MakeAppx.exe pack /d <path to directory that contains manifest> /p <output path>\MyPackage.msix /nv

Перед успешной установкой пакета с внешним расположением на целевом компьютере необходимо подписать его сертификатом, доверенным на целевом компьютере. Вы можете создать самозаверяющий сертификат для целей разработки и подписать пакет с внешним расположением с помощью SignTool, который доступен в пакете SDK для Windows.

В следующем примере показано, как подписать пакет с внешним расположением из командной строки.

SignTool.exe sign /fd SHA256 /a /f <path to certificate>\MyCertificate.pfx /p <certificate password> <path to package with external location>\MyPackage.msix

Добавление метаданных идентификатора пакета в манифест классического приложения

Вы также должны включить параллельный манифест приложения с классическим приложением. См. раздел Манифесты приложений (это файл, который объявляет такие вещи, как поддержка DPI, и внедряется в .exe приложения во время сборки). Включите в этот файл элемент msix с атрибутами, которые объявляют атрибуты удостоверения вашего приложения. Значения этих атрибутов использует операционная система для определения идентификатора приложения при запуске исполняемого файла.

В следующем примере показан параллельный манифест приложения с элементом msix.

<?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="Contoso.PhotoStoreApp"/>
  <msix xmlns="urn:schemas-microsoft-com:msix.v1"
          publisher="CN=Contoso"
          packageName="ContosoPhotoStore"
          applicationId="ContosoPhotoStore"
        />
</assembly>

Атрибуты элемента msix должны соответствовать этим значениям в манифесте пакета для пакета с внешним расположением:

  • Атрибуты packageName и publisher должны соответствовать атрибутам Name и Publisher в элементе Identity в манифесте пакета соответственно.
  • Атрибут applicationId должен соответствовать атрибуту Id элемента Application в манифесте пакета.

Регистрация пакета с внешним расположением во время выполнения

Чтобы предоставить удостоверению пакета классическому приложению, приложение должно зарегистрировать пакет с внешним расположением с помощью метода AddPackageByUriAsync класса PackageManager. Этот метод доступен в Windows 10 версии 2004 и более поздних. Вы можете добавить код в приложение, чтобы зарегистрировать пакет с внешним расположением при первом запуске приложения, или запустить код для регистрации пакета во время установки классического приложения (например, если вы используете MSI для установки классического приложения, можно запустить этот код из пользовательского действия).

В следующем примере показано, как зарегистрировать пакет с внешним расположением. Этот код создает объект AddPackageOptions, содержащий путь к внешнему расположению, на которое манифест пакета может ссылаться, чтобы указать содержимое вне пакета. Затем код передает этот объект методу AddPackageByUriAsync , чтобы зарегистрировать пакет с внешним расположением. Этот метод также получает расположение подписанного пакета с внешним расположением в виде URI. Более полный пример см StartUp.cs . в файле кода в соответствующем примере приложения (см . раздел "Пример приложения " в этом разделе).

private static bool registerPackageWithExternalLocation(string externalLocation, string pkgPath)
{
    bool registration = false;
    try
    {
        Uri externalUri = new Uri(externalLocation);
        Uri packageUri = new Uri(pkgPath);

        Console.WriteLine("exe Location {0}", externalLocation);
        Console.WriteLine("msix Address {0}", pkgPath);

        Console.WriteLine("  exe Uri {0}", externalUri);
        Console.WriteLine("  msix Uri {0}", packageUri);

        PackageManager packageManager = new PackageManager();

        // Declare use of an external location
        var options = new AddPackageOptions();
        options.ExternalLocationUri = externalUri;

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

        // Other progress and error-handling code omitted for brevity...
    }
}

Пример приложения

Ознакомьтесь с примером SparsePackages для полнофункциональным примером приложения, демонстрирующего предоставление удостоверения пакета классическому приложению с помощью пакета с внешним расположением. Дополнительные сведения о создании и запуске примера приведены в записи блога Identity, Registration and Activation of Non packaged Win32 Apps.

Этот пример содержит следующие компоненты:

  • Исходный код для приложения WPF с именем PhotoStoreDemo. Во время запуска приложение проверяет, работает ли оно с идентификатором. Если он не работает с удостоверением, он регистрирует пакет с внешним расположением, а затем перезапускает приложение. Дополнительную информацию о коде, который выполняет эти действия, см. в StartUp.cs.
  • Параллельный манифест приложения с именем PhotoStoreDemo.exe.manifest.
  • Манифест пакета с именем AppxManifest.xml.