Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
идентификатор пакета является уникальным идентификатором в пространстве и времени. Так же, как ДНК однозначно идентифицирует вас, идентификация пакета однозначно идентифицирует пакет.
Пакет содержит связанный набор битов (файлов и т. д.). У двух пакетов не может быть одного и того же удостоверения, и любое изменение данных, связанных с пакетом, требует присвоения нового удостоверения.
Что такое идентификатор пакета?
Идентификатор пакета — это логическая конструкция, уникально определяющая пакет. Удостоверение состоит из 5 частей:
- Имя: Это имя, выбранное разработчиком приложения. Microsoft Store обеспечивает уникальность всех имен приложений для всех разработчиков приложений в Магазине, но имена не гарантируют уникальность в общей экосистеме.
- Версия: Номер версии пакета. Разработчик приложений может выбрать произвольные номера версий, но должен обеспечить увеличение номеров версий с обновлениями.
- архитектура : архитектура процессора, на которую нацелен пакет. Одно и то же приложение может быть создано для различных архитектур процессора, и каждая сборка находится в собственном пакете.
-
ResourceId: Строка, выбранная разработчиком приложения для уникальной идентификации пакетов ресурсов, например различных языков или различных масштабов отображения. Пакеты ресурсов обычно являются нейтральными по архитектуре. Для пакетов ResourceId всегда
~. - Publisher: название разработчика приложения, указанное в сертификате подписи. Это теоретически уникально для каждого разработчика приложений, так как авторитетные центры сертификации используют уникальные реальные имена и удостоверения для заполнения поля имени субъекта сертификата.
Эта конструкция иногда называется 5-элементным кортежем .
Замечание
Неподписанные пакеты (1) по-прежнему требуют издателя, (2) издатель должен содержать маркер Неподписанный (OID.2.25.311729368913984317654407730594956997722=1), (3) маркер Неподписанный должен быть последним полем в строке издателя, и (4) нет сертификата или подписания для Неподписанного пакета.
Ограничения полей идентификаторов пакета
| Поле | Тип данных | Ограничения | Комментарии |
|---|---|---|---|
| Имя | Строка пакета | Мин: 3 Макс: 50 |
Допустимые значения для API проверки (см. строку пакета ) |
| Версия | DotQuad | Мин: 0.0.0.0 Макс: 65535.65535.65535.65535 |
Строковое представление использует десятеричную точечную нотацию, "Major.Minor.Build.Revision". |
| Архитектура | Перечисление | Min: Нет данных Максимум: нет данных |
Допустимые значения: "нейтральное", "x86", "x64", "arm", "arm64", "x86a64" |
| ResourceId (Идентификатор ресурса) | Строка пакета | Мин: 0 Макс: 30 |
Допустимые значения для API проверки (см. строку пакета ) |
| Издатель | Струна | Мин: 1 Макс: 8192 |
Допустимые значения для X.509 |
| Идентификатор издателя | Струна | Мин: 13 Макс. 13 |
Base32 закодированный вариант Crockford, т. е. [a-hjkmnp-tv-z0-9] |
Что такое строка пакета?
Строка пакета — это строка, которая позволяет использовать следующие символы:
- Допустимые входные символы (подмножество ASCII)
- Прописные буквы (U+0041 по U+005A)
- Строчные буквы (U+0061 по U+007A)
- Цифры (U+0030 до U+0039)
- Dot (U+002E)
- Dash (U+002D)
Следующие значения запрещены использовать в качестве строк пакета:
| Состояние | Запрещенные значения |
|---|---|
| Не равно | ".", ".", "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" |
| Не удается начать с | "con.", "prn.", "aux.", "nul.", "com1.", "com2.", "com3.", "com4.", "com5.", "com6.", "com7.", "com8.", "com9.", "lpt1.", "lpt2.", "lpt3.", "lpt4.", "lpt5.", "lpt6.", "lpt7.", "lpt8.", "lpt9.", "xn--" |
| Не удается завершить | "." |
| Нельзя содержать | .xn-- |
строки пакета
Поля name и resourceid идентификатора пакета являются строками пакета.
Объект PackageId
PackageId — это объект, содержащий пятикомпонентный кортеж в виде отдельных полей (Name, Version, Architecture, ResourceId, Publisher).
Полное имя пакета
Полное имя пакета
<Name>_<Version>_<Architecture>_<ResourceId>_<PublisherId>
Например, одно полное имя пакета для приложения "Фотографии Windows" — "Microsoft.Windows.Photos_2020.20090.1002.0_x64__8wekyb3d8bbwe", Где "Microsoft.Windows.Photos" — это имя: "2020.20090.1002.0" — номер версии, "x64" — это целевая архитектура процессора, идентификатор ресурса пуст (содержимое между последними двумя подчеркиваниями) и "8wekyb3d8bbwe" — это идентификатор издателя для Майкрософт.
Полное имя пакета однозначно определяет пакет или комплект MSIX. Ошибка возникает, если два пакета или комплекта имеют разное содержимое, но одинаковое полное имя пакета.
Замечание
MSIX — это новое имя для предыдущего термина APPX. Дополнительные сведения см. в разделе "Что такое MSIX"?
Имя семейства пакетов
Имя семейства пакетов — это непрозрачная строка, производная только от двух частей идентичности пакета: имени и издателя .
<Name>_<PublisherId>
Например, имя семейства пакетов приложения "Фотографии Windows" — "Microsoft.Windows.Photos_8wekyb3d8bbwe", где "Microsoft.Windows.Photos" — это имя, а "8wekyb3d8bbwe" — это идентификатор издателя для Майкрософт.
Имя семейства пакетов часто рассматривается как полное имя пакета, не содержащее версии.
Замечание
Это не так, так как имя семейства пакетов также не имеет архитектуры и идентификатора ресурса.
Замечание
Данные и безопасность обычно охватывают семейство пакетов. Например, это будет неудачный опыт, если вы настроите приложение Блокнота, установленное из пакета версии 1.0.0.0, для включения переноса по словам. Затем блокнот был обновлен до версии 1.0.0.1, а данные конфигурации не были перенесены в более новую версию пакета.
Идентификатор издателя
Имя семейства пакетов — это строка с форматом:
<name>_<publisherid>
Где идентификатор издателя имеет некоторые очень конкретные свойства:
- Производный от издателя
- MinLength = MaxLength = 13 chars [фиксированный размер]
- Допустимые символы (как регулярное выражение) = a-hj-km-np-tv-z0-9
- Base-32, Crockford Variant, т. е. буквенно-цифровой (A-Z0-9), кроме I (глаз), L (ell), O (oh) или U (you)
- Порядковый регистр не учитывается для сравнения --- ABCDEFABCDEFG == abcdefabcdefg
Таким образом, вы никогда не увидите % : \ / " ? или другие символы в идентификаторе издателя.
Дополнительные сведения см. в PackageFamilyNameFromId и PackageNameAndPublisherIdFromFamilyName.
Идентификатор издателя часто называется PublisherId.
Почему существует идентификатор издателя?
Идентификатор издателя существует, потому что издатель должен соответствовать имени или подписи вашего сертификата X.509, таким образом:
- Это может быть очень большим (длина <= 8192 символов)
- Он может включать символы, которые являются странными или ограниченными (обратная косая черта и т. д.)
Эти проблемы могут сделать некоторые строки X.509 неловкими или невозможными для использования в файловой системе, реестре, URL-адресах и других контекстах.
Как создать PublisherId?
Используйте PackageNameAndPublisherIdFromFamilyName для извлечения PublisherId из объекта PackageFamilyName.
Используйте PackageIdFromFullName для извлечения PublisherId из объекта PackageFullName.
Редко необходимо создавать PublisherId из Publisher, но это можно сделать, используя доступные API.
#include <appmodel.h>
HRESULT PublisherIdFromPublisher(
_In_ PCWSTR publisher,
_Out_writes_(PACKAGE_PUBLISHERID_MAX_LENGTH + 1) PWSTR publisherId)
{
PCWSTR name{ L"xyz" };
const size_t nameLength{ ARRAYSIZE(L"xyz") - 1 };
const size_t offsetToPublisherId{ nameLength + 1 }; // xyz_...publisherid...
PACKAGE_ID id{};
id.name = name;
id.publisher = publisher;
WCHAR familyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1]{};
UINT32 n{ ARRAYSIZE(familyName) };
RETURN_IF_WIN32_ERROR(PackageFamilyNameFromId(&id, &n, familyName));
RETURN_IF_FAILED(StringCchCopyW(publisherId, PACKAGE_PUBLISHERID_MAX_LENGTH + 1, familyName + offsetToPublisherId));
return S_OK;
}
Ниже приведена классическая реализация Windows C для той же операции:
#include <appmodel.h>
HRESULT PublisherIdFromPublisher(
_In_ PCWSTR publisher,
_Out_writes_(PACKAGE_PUBLISHERID_MAX_LENGTH + 1) PWSTR publisherId)
{
const WCHAR c_name[]{ L"xyz" };
const UINT32 c_nameLength{ ARRAYSIZE(c_name) - 1 };
PACKAGE_ID id{};
id.name = c_name;
id.publisher = publisher;
WCHAR familyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1]{};
UINT32 n{ ARRAYSIZE(familyName) };
RETURN_IF_WIN32_ERROR(PackageFamilyNameFromId(&id, &n, familyName));
RETURN_IF_FAILED(StringCchCopyW(publisherId, PACKAGE_PUBLISHERID_MAX_LENGTH + 1, familyName + c_nameLength + 1));
return S_OK;
}
Это создает PublisherId путем преобразования идентификатора пакета в имя семейства пакетов с результирующим форматом xyz_<publisherid>. Этот рецепт является стабильным и надежным.
Это требует только компиляции с использованием appmodel.h из пакета SDK и связывания с kernel32.lib (или kernelbase.lib, onecore.lib, или api-ms-win-appmodel-runtime-l1.lib при использовании APIsets).
Понимание архитектуры процессора в идентификации пакета
Распространенное недоразумение заключается в том, что Architecture=x64 пакет может содержать только код x64. Это не верно. Это означает, что пакет работает в системах, поддерживающих код x64, и может использоваться приложениями x64. Вы можете сделать пакет, содержащий только PDF-файлы, но объявить его <Identity Architecture=x64...> , так как он предназначен только для установки в системах, совместимых с x64 (например, пакеты x64 могут быть установлены только в системах x64 и (с Windows 11) Arm64, так как системы x86, Arm и Windows 10 Arm64 не поддерживают x64.
Еще более неправильно, Architecture=neutralне означает, что пакет не содержит исполняемого кода. Это означает, что пакет работает на всех архитектурах. Например, можно сделать пакет, содержащий API шифрования AES, написанный на JavaScript, Python, C#, и т. д., но производительность не допускается в системах Arm64. Таким образом, вы включаете оптимизированный двоичный файл Arm64 и реализуете API для его обработки:
void Encrypt(...)
{
HANDLE h{};
if (GetCpu() == arm64)
{
h = LoadLibrary(GetCurrentPackagePath() + "\bin\encrypt-arm64.dll")
p = GetProcAddress(h, "Encrypt")
return (*p)(...)
}
else
{
// ...call other implementation...
}
}
Можно также сделать нейтральный пакет с несколькими вариантами.
\
bin\
encrypt-x86.dll
encrypt-x64.dll
encrypt-arm.dll
encrypt-arm64.dll
Затем разработчики могут использовать LoadLibrary("bin\encrypt-" + cpu + ".dll"), чтобы получить подходящий двоичный файл для своего процесса в процессе выполнения.
Как правило, нейтральные пакеты не имеют зависящего от архитектуры содержимого, но оно может быть. Существуют ограничения на то, что можно сделать (например, можно создать пакет Блокнота, содержащий notepad.exe, скомпилированный для x86 + x64 + arm + arm64, но appxmanifest.xml может объявлять только <Application Executable=...>, указывающий на один из них). Учитывая, что есть пакеты, которые позволяют устанавливать только необходимые биты, это очень редкое дело. Это не незаконно, просто продвинутое и экзотическое.
Кроме того, Architecture=x86 или наличие x64|arm|arm64 не означает, что пакет содержит только исполняемый код для указанной архитектуры. Это просто подавляющее частое дело.
Замечание
При обсуждении "кода" или "исполняемого кода" в этом контексте мы ссылаемся на переносимые исполняемые файлы (PE).
Чувствителен ли регистр идентификатора пакета?
В основном нет, но Publisher чувствителен к регистру.
Остальные поля (Name, ResourceId, PublisherId, PackageFullName и PackageFamilyName) не заполнены. Эти поля сохраняют регистр, но сравнивают регистр без учета регистра.
Идентификатор пакета и идентификатор приложения
Идентификатор пакета и идентификатор приложения — связанные, но разные понятия. Понимание разницы помогает избежать распространенного неправильного представления: что приложение является его пакетом.
- Пакет — это единица распространения и развертывания. Вы устанавливаете, обновляете или удаляете пакет в целом.
- Приложение — это пользовательская конструкция — коллекция окон, процессов и других ресурсов, которые вместе формируют одну программу независимо от того, как она реализована (один процесс, несколько процессов или даже несколько приложений, совместно использующих процесс).
Приложения распределяются по пакетам, но они не совпадают с пакетами. Один пакет может объявлять в любом месте от нуля до ста приложений, а некоторые типы пакетов (например, пакеты платформы и пакеты ресурсов) не могут объявлять приложения вообще.
ApplicationUserModelID (AUMID)
Для упакованных приложений идентификатор приложения представлен ApplicationUserModelID (также известный как AppUserModelId или AUMID). Эта строка позволяет Windows связывать windows, процессы и ресурсы с определенным приложением независимо от внутренней архитектуры приложения.
Другими словами:
- Идентификатор пакета (кортеж из 5 частей, описанный выше) однозначно определяет пакет.
- Идентификатор приложения (AUMID) однозначно идентифицирует приложение в пределах этого пакета.
Windows использует AUMID для идентификации приложений во время выполнения — например, чтобы группировать окна на панели задач, направлять уведомления и управлять жизненным циклом приложений. AUMID объявляется в элементе приложения манифеста пакета и является производным от имени семейства пакетов и объявленного идентификатора приложения.
Tip
Более подробное изучение того, почему приложения не являются пакетами и как AUMID мостит две концепции, см. в статье "Приложения не являются пакетами в блоге Внутри MSIX".
См. также
Windows developer