Присвоение идентичности пакету путем упаковки с использованием внешнего места вручную.

Почему это сделать? Предоставление вашему приложению удостоверения пакета (также называемого пакетом sparse или упаковкой с внешним расположением) разблокирует функции платформы Windows, которые в противном случае недоступны для неупакованных приложений: уведомления Toast и push-уведомления, фоновые задачи, расширения для приложений, целевые объекты общего доступа, сопоставления файлов, задачи запуска, запросы согласия на сбор конфиденциальной информации и API-интерфейсы Windows AI Foundry — все без необходимости перехода на полную упаковку MSIX или изменения существующего установщика.

Дополнительные сведения о мотивах добавления удостоверения пакета, а также различия между сборкой пакетов в Visual Studio и их создании вручную см. в разделе Overview.

В этом разделе описывается, как создать и зарегистрировать пакет удостоверений вручную. Сведения о создании пакета удостоверений в Visual Studio см. в разделе Присвоение идентификатора пакету, объединив его с внешним расположением в Visual Studio.

Ниже приведены шаги (подробно описанные в этом разделе) для создания и регистрации пакета удостоверений вручную:

  1. Создайте манифест пакета для пакета идентификации
  2. Создание и подписание пакета удостоверений
  3. Добавьте метаданные удостоверения в манифесты настольных приложений
  4. Зарегистрируйте пакет удостоверений в установщике
  5. Необязательные шаги

Создайте манифест для пакета идентификации

Первым шагом к созданию пакета идентификации является создание манифеста пакета на основе приведенного ниже шаблона. Это манифест MSIX, но используется только для идентификации и не изменяет поведение среды выполнения приложения.

<?xml version="1.0" encoding="utf-8"?>
<Package IgnorableNamespaces="uap uap10"
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
  <Identity Name="ContosoPhotoStore" Publisher="CN=Contoso" Version="1.0.0.0" ProcessorArchitecture="neutral" />
  <Properties>
    <DisplayName>Contoso PhotoStore</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.19041.0" MaxVersionTested="10.0.26100.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="Contoso PhotoStore App" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" />
    </Application>
  </Applications>
</Package>

Обратите внимание на следующие важные сведения об этом манифесте:

  • Identity Заполните атрибуты элемента сведениями о приложении
    • Name — требуемое имя пакета удостоверений
    • Publisher должен соответствовать Subject сертификата, используемого для подписи приложения.
    • Version — это требуемая версия пакета удостоверений. Распространенная практика заключается в выравнивании версии пакета удостоверений с версией приложения. Вы не сможете зарегистрировать версию пакета удостоверений в системе, если эта версия пакета уже зарегистрирована. Сначала необходимо отменить регистрацию существующего пакета, чтобы переустановить пакет с той же версией.
    • ProcessorArchitecture должен быть neutral как указано, чтобы пакет идентификатора работал на всех архитектурах (x86, x64 и ARM64)
  • Заполните элементы DisplayName и PublisherDisplayName подробностями вашего приложения
    • Если в манифест помимо простого удостоверения не добавляются дополнительные функции, эти значения не отображаются нигде.
  • Обновите элемент Logo на относительный путь в каталоге установки приложения, который должен ссылаться на изображение .png, .jpgили .jpeg.
  • Убедитесь, что элемент AllowExternalContent установлен на true, как показано, для повторного использования вашего существующего установщика.
  • Установите TargetDeviceFamilyMinVersion и MaxVersionTested как указано ниже.
    • MinVersion Выберите значение на основе минимально поддерживаемой ОС:
      • 10.0.19041.0 — рекомендуется для максимального охвата Windows 10 и Windows 11
      • 10.0.26100.0 — используйте это только в том случае, если приложение предназначено только для Windows 11 версии 24H2 или более поздней версии.
    • Установите MaxVersionTested в 10.0.26100.0, как показано
    • Примечание. В сборке Windows 10.0.19041.0 была представлена функция AllowExternalContent. Если ваше приложение работает на более ранних версиях ОС, чем указано, необходимо выполнить проверку версии ОС в установщике и не регистрировать пакет идентификации на версиях ОС, которые старше 10.0.19041.0. См. раздел "Регистрация пакета удостоверений" в установщике.
  • Убедитесь, что возможности runFullTrust и unvirtualizedResources объявлены так, как показано для совместимости с Win32.
  • Добавьте элемент Application, как показано, для каждого исполняемого файла, связанного с вашим приложением.
    • Убедитесь, что TrustLevel является mediumIL, а RuntimeBehavior является win32App, как показано для совместимости с Win32.
  • VisualElements Дочерний элемент является обязательным, но AppListEntry="none" атрибут гарантирует, что пакет удостоверений не отображается среди установленных приложений.
    • DisplayName Обновите и Description атрибуты с соответствующими сведениями и оставьте другие атрибуты, как показано (пути к указанному изображению не нужно разрешать).
    • См. Локализация и визуальные ресурсы для сценариев, в которых здесь может потребоваться локализация и изображения.

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

Создание и подписание пакета идентификации

После создания манифеста пакета удостоверений создайте пакет удостоверений с помощью средства MakeAppx.exe в пакете SDK Windows.

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

Примечание. Флаг /nv требуется для обхода проверки пути к файлам, на которые ссылается ссылка, в манифесте.

Для установки на компьютеры конечных пользователей пакет удостоверений должен быть подписан сертификатом, которому доверяют на целевом компьютере. Вы можете создать новый самозаверяющий сертификат для целей разработки и подписать пакет удостоверения с помощью SignTool> который доступен в пакете SDK Windows, но для регистрации пакета на конечных компьютерах потребуется рабочий сертификат из ИТ-отдела или службы, например Azure Trusted Signing.

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

Это важно

При использовании самозаверяющего сертификата для локальной разработки необходимо добавить его общедоступный сертификат в хранилище сертификатов доверенных людей , прежде чем Add-AppxPackage принять его. Без этого шага регистрация завершается ошибкой CERT_E_UNTRUSTEDROOT (0x800B0109).

Сохраните закрытый файл — он содержит закрытый .pfx ключ и должен использоваться только для подписи. На шаге доверия экспортируйте общедоступный сертификат .cer (только) и импортируйте.

$cert = Get-PfxCertificate -FilePath "<path>\MyCertificate.pfx"
Export-Certificate -Cert $cert -FilePath "<path>\MyCertificate.cer"
Import-Certificate -FilePath "<path>\MyCertificate.cer" `
    -CertStoreLocation Cert:\CurrentUser\TrustedPeople

Для установки на уровне компьютера используйте Cert:\LocalMachine\TrustedPeople (необходимо повысить права доступа).

Для производственных сертификатов, выданных доверенным УЦ, не требуется этот шаг.

Примечание: О том, как создавать и подписывать пакет удостоверений в конвейере CI/CD с производственными сертификатами, см. Обзор MSIX и конвейера CI/CD для примеров.

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

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

В Visual Studio можно добавить манифест приложения в исполняемый проект, открыв контекстное меню проекта и выбрав в нём пункты "Добавить", "Новый элемент" и "Файл манифеста приложения".

Ниже приведен пример фрагмента манифеста приложения, демонстрирующего элемент msix, необходимый для подключения бинарных файлов к метаданным из пакета удостоверений.

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="0.0.0.0" name="ContosoPhotoStore"/>
  <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 элемента в манифесте пакета удостоверений.

Регистрация идентификационного пакета в установщике

Последним шагом для связывания удостоверения с приложением является регистрация пакета удостоверений в установщике и связывание его с каталогом установки приложения.

PowerShell

Выполнение powershell.exe с правильными параметрами — самый простой способ регистрации пакета. Рекомендации отличаются для установок на пользователя и на всю систему.

Для каждого пользователя (PowerShell)

Чтобы зарегистрировать пакет идентификации во время персональной установки:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Add-AppxPackage -Path <PackagePath> -ExternalLocation <ExternalLocation>"
  • Задайте <PackagePath> абсолютный путь к подписанному пакету удостоверений, создаваемому на предыдущем шаге (с именем файла).
  • Задайте <ExternalLocation> абсолютный путь к каталогу установки приложения (без имен исполняемых файлов).

Чтобы отменить регистрацию пакета идентификаций во время удаления пользователя:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Get-AppxPackage <PackageName> | Remove-AppxPackage"
  • Задайте <PackageName> имя пакета, определенное в манифесте пакета удостоверений (атрибут Name элемента Identity )

Per-Machine (PowerShell)

Чтобы зарегистрировать пакет идентификации во время установки для всего компьютера:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Add-AppxPackage -Stage <PackagePath> -ExternalLocation <ExternalLocation>; Add-AppxProvisionedPackage -Online -PackagePath <PackagePath>"
  • Задайте <PackagePath> абсолютный путь к подписанному пакету удостоверений, создаваемому на предыдущем шаге (с именем файла).
  • Задайте <ExternalLocation> абсолютный путь к каталогу установки приложения (без имен исполняемых файлов).

Чтобы отменить регистрацию пакета удостоверений во время удаления на уровне компьютера:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "$packages = Get-AppxPackage -AllUsers -Name <PackageName>; $provisioned = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq '<PackageName>' }; foreach ($p in $provisioned) { Remove-AppxProvisionedPackage -PackageName $p.PackageName -Online }; foreach ($package in $packages) { Remove-AppxPackage -Package $package.PackageFullName -AllUsers }"
  • Задайте <PackageName> имя пакета, определенное в манифесте пакета удостоверений (атрибут Name элемента Identity )

API-интерфейсы PackageManager

Если вы предпочитаете вызывать API ОС для регистрации и отмены регистрации пакета удостоверений, API PackageManager предоставляет эквивалентные функциональные возможности PowerShell. Рекомендации отличаются для установок на пользователя и на всю систему.

Ниже приведены фрагменты кода, демонстрирующие API. Готовый к работе код в C# и C++см. в разделе "Примеры приложений".

"Для каждого пользователя (PackageManager)"

Приведенный ниже код демонстрирует регистрацию пакета удостоверений с помощью метода AddPackageByUriAsync и отмены регистрации пакета удостоверений с помощью метода RemovePackageAsync .

using Windows.Management.Deployment;

...

// Register the identity package during install

var externalUri = new Uri(externalLocation);
var packageUri = new Uri(packagePath);

var packageManager = new PackageManager();

var options = new AddPackageOptions();
options.ExternalLocationUri = externalUri;

var result = await packageManager.AddPackageByUriAsync(packageUri, options);
if (result.ExtendedErrorCode != 0)
{
    throw new Exception($"Package registration failed: {result.ErrorText} (0x{result.ExtendedErrorCode:X8})");
}

...

// Unregister the identity package during uninstall

var packageManager = new PackageManager();
var packages = packageManager.FindPackagesForUserWithPackageTypes("", "<IdentityPackageFamilyName>", PackageTypes.Main);
foreach (var package in packages)
{
  await packageManager.RemovePackageAsync(package.Id.FullName);
}

Обратите внимание на следующие важные сведения об этом коде:

  • Задайте externalLocationабсолютный путь к каталогу установки приложения (без имен исполняемых файлов). new Uri(somePath) создает универсальный file:/// код ресурса (URI) в соответствии с требованиями API.
  • Задайте packagePathабсолютный путь к подписанному пакету удостоверений, создаваемому на предыдущем шаге (с именем файла)
  • <IdentityPackageFamilyName> можно найти, выполнив команду PowerShell Get-AppxPackage <IdentityPackageName> на системе, где зарегистрирован пакет идентификации. Свойство PackageFamilyName содержит значение, используемое здесь.
  • Проверьте result.ExtendedErrorCode после регистрации для получения доступных к исправлению сведений об ошибках. См. сведения об устранении неполадок для распространенных кодов ошибок.

Пер-Машина (PackageManager)

Приведенный ниже код демонстрирует регистрацию пакета удостоверений с помощью методов StagePackageByUriAsync и ProvisionPackageForAllUsersAsync и отмены регистрации пакета удостоверений с помощью методов DeprovisionPackageForAllUsersAsync и RemovePackageAsync .

// Register the identity package during install

var externalUri = new Uri(externalLocation);
var packageUri = new Uri(packagePath);

var packageManager = new PackageManager();

var options = new StagePackageOptions();
options.ExternalLocationUri = externalUri;

await packageManager.StagePackageByUriAsync(packageUri, options);
var packageFamilyName = "<IdentityPackageFamilyName>";
await packageManager.ProvisionPackageForAllUsersAsync(packageFamilyName);

...

// Unregister the identity package during uninstall

var packageManager = new PackageManager();

var packages = packageManager.FindPackagesForUserWithPackageTypes("", "<IdentityPackageFamilyName>", PackageTypes.Main);
foreach (var package in packages)
{
  await packageManager.DeprovisionPackageForAllUsersAsync(package.Id.FullName);
  await packageManager.RemovePackageAsync(package.Id.FullName, RemovalOptions.RemoveForAllUsers);
}

Обратите внимание на следующие важные сведения об этом коде:

  • Задайте externalLocation абсолютный путь к каталогу установки приложения (без имен исполняемых файлов)
  • Задайте packagePath абсолютный путь к подписанному пакету удостоверений, создаваемому на предыдущем шаге (с именем файла)
  • <IdentityPackageFamilyName> можно найти, выполнив команду PowerShell Get-AppxPackage <IdentityPackageName> на системе, где зарегистрирован пакет идентификации. Свойство PackageFamilyName содержит значение, используемое здесь.

Troubleshooting

В таблице ниже перечислены наиболее распространенные ошибки при регистрации пакета удостоверений и их исправлении.

Код ошибки Симптом Причина Исправление
0x800B0109 / CERT_E_UNTRUSTEDROOT Add-AppxPackage или AddPackageByUriAsync немедленно завершается сбоем Самоподписанный сертификат не находится в хранилище Доверенные лица Выполните описанный выше шаг доверия сертификатов, чтобы импортировать публичный .cer объект в Cert:\CurrentUser\TrustedPeople
0x80073CF9 Регистрация завершается сбоем с сообщением "версия уже зарегистрирована". На этом компьютере уже зарегистрирована та же версия пакета. Отмена регистрации существующего пакета (Remove-AppxPackage или RemovePackageAsync), а затем повторная регистрация
0x80073D54 Регистрация завершается успешно, но идентификационные данные отсутствуют в процессе выполнения publisher, packageNameили applicationId в параллельном манифесте приложения (msix элемент) не совпадают с манифестом пакета удостоверений Убедитесь, что Publisher/Name/Application Id идентичны в обоих манифестах — см. Добавить метаданные идентичности
идентификатор отсутствует во время выполнения (ошибки нет) Package.Current имеет значение NULL или GetPackage() возвращает ничего не ExternalLocation Путь, переданный при регистрации, не соответствует каталогу, в котором приложение фактически выполняется. Убедитесь, что переданный абсолютный путь ExternalLocation точно совпадает с каталогом установки приложения.
0x80073CF6 Регистрация неудается с ошибкой "недопустимый манифест" XML манифеста неправильно сформирован или отсутствует обязательный атрибут Проверьте манифест на наличие ошибок схемы с помощью MakeAppx.exe pack. Убедитесь, что uap10:AllowExternalContenttrue и возможность runFullTrust задекларирована

Подсказка

Для более полной диагностики проверьте Windows Просмотр событий в разделе Applications and Services Logs > Майкрософт > Windows > AppxDeployment-Server. Он регистрирует ошибку полного развертывания с контекстом, который не всегда отображается в результатах API или выходных данных PowerShell.

Примеры приложений

Примеры PackageWithExternalLocation см. в полнофункциональных приложениях C# и C++, демонстрирующих регистрацию и отмену регистрации пакета удостоверений.

Другие необязательные шаги

Локализация и визуальные ресурсы

Некоторые функции, которые понимают идентичность пакета, могут привести к отображению строк и изображений из манифеста пакета идентичности в операционной системе Windows. Рассмотрим пример.

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

Сведения о локализации строк в манифесте пакета удостоверений см. в разделе "Локализация манифеста".

При указании путей к изображениям в атрибутах VisualElements в манифесте пакета удостоверений, указанные пути должны быть относительными путями в каталоге установки вашего приложения, которые разрешаются к изображениям типа .png, .jpgили .jpeg. Имена атрибутов указывают ожидаемые размеры изображений (150x150 и 40x40).