Delen via


Een overzicht van pakketidentiteit in Windows-apps

Pakketidentiteit is een unieke id voor ruimte en tijd. Net zoals uw DNA u uniek identificeert, identificeert pakketidentiteit een pakket op unieke wijze.

Een pakket heeft een gekoppelde set bits (bestanden, enzovoort). Er zijn geen twee pakketten met dezelfde identiteit en eventuele wijzigingen in de bits die aan een pakket zijn gekoppeld, hebben een andere identiteit nodig.

Wat is pakketidentiteit?

Een pakketidentiteit is een logische constructie die een pakket uniek identificeert. De identiteit heeft 5 onderdelen:

  • naam: Dit is een naam die is gekozen door de app-ontwikkelaar. De Microsoft Store dwingt de uniekheid van alle app-namen af voor alle app-ontwikkelaars in de Store, maar namen zijn niet gegarandeerd uniek in het algemene ecosysteem.
  • versie: versienummer van het pakket. De app-ontwikkelaar kan willekeurige versienummers kiezen, maar moet ervoor zorgen dat versienummers toenemen met updates.
  • Architectuur: De processorarchitectuur waarop het pakket betrekking heeft. Dezelfde app kan worden gebouwd op basis van verschillende processorarchitecturen, waarbij elke build zich in een eigen pakket bevindt.
  • ResourceId: een tekenreeks die door de app-ontwikkelaar is gekozen om resourcepakketten uniek te identificeren, bijvoorbeeld verschillende talen of verschillende weergaveschalen. Resourcepakketten zijn doorgaans architectuurneutraal. Voor bundels is de ResourceId altijd ~.
  • Publisher: De onderwerpnaam van de app-ontwikkelaar zoals geïdentificeerd door hun handtekeningcertificaat. Dit is theoretisch uniek voor elke app-ontwikkelaar, omdat betrouwbare certificeringsinstanties unieke echte namen en identiteiten gebruiken om het onderwerpnaamveld van het certificaat te vullen.

Deze constructie wordt soms de 5-delige tuplegenoemd.

Opmerking

Niet-ondertekende pakketten (1) nog steeds een Publishervereisen , (2) moet de Publisher- de markering Niet-ondertekend (OID.2.25.31172936891398431) bevatten7654407730594956997722=1), (3) de niet-ondertekende markering moet het laatste veld in de Publisher tekenreeks zijn en (4) er geen certificaat of ondertekening is voor een niet-ondertekend pakket.

Limieten voor pakketidentiteitsvelden

Veld Gegevenstype Grenzen Opmerkingen
Naam Pakketreeks Min. 3
Max: 50
Toegestane waarden per Validatie-API (zie pakkettekenreeks)
Versie DotQuad Minimaal: 0.0.0.0
Max: 65535.65535.65535.65535
Tekenreeks gebruikt decimale gestippelde notatie, "Major.Minor.Build.Revision"
Architectuur Opsomming Min.: n.v.t.
Max: n.v.t.
Toegestane waarden zijn "neutraal", "x86", "x64", "arm", "arm64", "x86a64"
Bron Id Pakketreeks Min. 0
Max: 30
Toegestane waarden per Validatie-API (zie pakkettekenreeks)
Uitgever Snaar / Touwtje Min. 1
Max: 8192
Toegestane waarden per X.509
Uitgevers-ID Snaar / Touwtje Minuten: 13
Max: 13
Gecodeerd in Base32, Crockford variant, d.w.z. [a-hjkmnp-tv-z0-9]

Wat is een pakketstring?

Een pakkettekenreeks is een tekenreeks die de volgende tekens toestaat:

  • Toegestane invoertekens (ASCII-subset)
    • Hoofdletters (U+0041 thru U+005A)
    • Kleine letters (U+0061 t/m U+007A)
    • Getallen (U+0030 thru U+0039)
    • Punt (U+002E)
    • Streepje / Koppelteken (U+002D)

De volgende waarden mogen niet worden gebruikt als pakkettekenreeksen:

Conditie Verboden waarden
Kan niet gelijk zijn aan ".", "..", "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
Kan niet beginnen met "con.", "prn.", "aux.", "nul.", "com1.", "com2.", "com3.", "com4.", "com5.", "com6.", "com7.", "com8.", "com9.", "lpt1.", "lpt2.", "lpt3.", "lpt4.", "lpt5.", "lpt6.", "lpt7.", "lpt8.", "lpt9.", "xn--"
Kan niet eindigen met "."
Kan niet bevatten .xn--

Een pakkettekenreeks moet worden vergeleken door gebruik te maken van een ordinale hoofdletterongevoelige vergelijkings-API (bijvoorbeeld _wcsicmp).

De name- en resourceid-velden van pakketidentiteit zijn pakkettekenreeksen.

PackageId-object

Een PackageId- is een object met de 5-delige tuple als afzonderlijke velden (Name, Version, Architecture, ResourceId, Publisher).

Volledige naam van pakket

Een volledige pakketnaam is een ondoorzichtige tekenreeks die is afgeleid van alle vijf delen van de identiteit van een pakket (naam, versie, architectuur, resourceid en uitgever)

<Name>_<Version>_<Architecture>_<ResourceId>_<PublisherId>

Een volledige pakketnaam voor de app Windows Foto's is bijvoorbeeld 'Microsoft.Windows.Photos_2020.20090.1002.0_x64__8wekyb3d8bbwe', waarbij 'Microsoft.Windows.Photos' de naam is, '2020.20090.1002.0' het versienummer, 'x64' de doelprocessorarchitectuur is, de resource-id leeg is (geen inhoud tussen de laatste twee onderstrepingstekens), en '8wekyb3d8bbwe' de uitgevers-id voor Microsoft is.

De volledige naam van het pakket identificeert een MSIX- pakket of bundel. Er is een fout opgetreden bij het hebben van twee pakketten of bundels met verschillende inhoud, maar met dezelfde volledige naam van het pakket.

Opmerking

MSIX- is de nieuwe naam voor de vorige term APPX-. Voor meer informatie, zie Wat is MSIX?

Familienaam van pakket

Een Pakketfamilienaam is een ondoorzichtige reeks tekens die is afgeleid van slechts twee delen van een pakketidentiteit: naam en uitgever.

<Name>_<PublisherId>

De pakketfamilienaam van de app Windows-foto's is bijvoorbeeld 'Microsoft.Windows.Photos_8wekyb3d8bbwe', waarbij 'Microsoft.Windows.Photos' de naam is en '8wekyb3d8bbwe' de uitgever-id voor Microsoft is.

Familienaam van pakket wordt vaak aangeduid als een volledige pakketnaam met versieloze pakketten.

Opmerking

Dit is niet strikt waar, omdat pakketfamilienaam ook architectuur en resource-id mist.

Opmerking

Gegevens en beveiliging zijn doorgaans beperkt tot een pakketfamilie. Het zou bijvoorbeeld een slechte ervaring zijn als u de Kladblok-app hebt geconfigureerd die is geïnstalleerd vanuit een Kladblok-pakket versie 1.0.0.0 om Wordwrap in te schakelen. Daarna werd Kladblok bijgewerkt naar 1.0.0.1 en werden uw configuratiegegevens niet overgedragen naar de nieuwere pakketversie.

Uitgever-id

Een pakketfamilienaam is een tekenreeks met de indeling:

<name>_<publisherid>

waarbij publisher-id een aantal zeer specifieke eigenschappen heeft:

  • Afgeleid van Publisher
  • MinLength = MaxLength = 13 tekens [vaste grootte]
  • Toegestane tekens (als regex) = a-hj-km-np-tv-z0-9
    • Basis-32, Crockford Variant, d.w.z. alfanumeriek (A-Z0-9), behalve geen I (oog), L (ell), O (oh) of U (u)
  • Ordinaal hoofdletterongevoelig voor vergelijkingen --- ABCDEFABCDEFG == abcdefabcdefg

Dus zul je nooit % zien: \ / " ? of andere tekens in een Publisher-ID.

Zie PackageFamilyNameFromId en PackageNameAndPublisherIdFromFamilyName voor meer informatie.

Publisher Id wordt vaak PublisherId genoemd.

Waarom bestaat publisher-id?

Publisher-id bestaat omdat Publisher moet overeenkomen met de X.509-naam/ondertekenaar van uw certificaat, dus:

  • Het kan erg groot zijn (lengte <= 8192 tekens)
  • Het kan tekens bevatten die onhandig of beperkt zijn (backslash, enzovoort)

Deze problemen kunnen ervoor zorgen dat sommige X.509-tekenreeksen onhandig of onmogelijk te gebruiken zijn in het bestandssysteem, register, URL's en andere contexten.

Hoe maak ik een PublisherId?

Gebruik PackageNameAndPublisherIdFromFamilyName om de PublisherId uit een PackageFamilyNamete extraheren.

Gebruik PackageIdFromFullName om de PublisherId uit een PackageFullNamete extraheren.

Het is zelden nodig om een PublisherId te maken op basis van Publisher, maar dit kan worden gedaan met het gebruik van beschikbare API's:

#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{ name + 1 }; // xyz_...publisherid...
    PACKAGE_ID id{};
    id.name = name;
    id.publisher = publisher;
 
    WCHAR familyName[PACKAGE_PUBLISHERID_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;
}

Hier volgt een klassieke Windows C-implementatie van dezelfde bewerking:

#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_nameForPublisherToPublisherId) - 1 };

    PACKAGE_ID id{};
    id.name = c_name;
    id.publisher = publisher;
    WCHAR familyName[PACKAGE_PUBLISHERID_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;
}

Hiermee maakt u de PublisherId door een pakket-id te converteren naar een pakketfamilienaam met de resulterende indeling xyz_<publisherid>. Dit recept is stabiel en betrouwbaar.

Hiervoor hoeft u alleen te compileren met appmodel.h vanuit de SDK en verbinding te maken met kernel32.lib (of kernelbase.lib, onecore.lib of api-ms-win-appmodel-runtime-l1.lib als u API's gebruikt).

Begrip van processorarchitectuur in pakketidentiteit

Een veelvoorkomend misverstand is dat Architecture=x64 betekent dat het pakket alleen x64-code kan bevatten. Dit is niet waar. Dit betekent dat het pakket werkt op systemen die x64-code ondersteunen en kunnen worden gebruikt door x64-apps. U kunt een pakket met alleen PDF-bestanden maken, maar declareren met <Identity Architecture=x64...> omdat het alleen bedoeld is om te worden geïnstalleerd op x64-compatibele systemen (bijvoorbeeld x64-pakketten kunnen alleen worden geïnstalleerd op x64- en (vanaf Windows 11) Arm64-systemen, omdat x86-, Arm- en Windows 10 Arm64-systemen geen ondersteuning bieden voor x64).

Nog meer verkeerd begrepen, Architecture=neutralniet betekent dat het pakket geen uitvoerbare code bevat. Dit betekent dat het pakket op alle architecturen werkt. U kunt bijvoorbeeld een pakket maken met een AES-versleutelings-API die is geschreven in JavaScript, Python, C#, enzovoort, maar de prestaties zijn niet acceptabel op Arm64-systemen. U neemt dus een geoptimaliseerd arm64-binair bestand op en implementeert de API om deze te verwerken:

void Encrypt(...)
{
    HANDLE h{};
    if (GetCpu() == arm64)
    {
        h = LoadLibrary(GetCurrentPackagePath() + "\bin\encrypt-arm64.dll")
        p = GetProcAddress(h, "Encrypt")
        return (*p)(...)
    }
    else
    {
        // ...call other implementation...
    }
}

U kunt ook een neutraal pakket maken met meerdere varianten:

\
    bin\
        encrypt-x86.dll
        encrypt-x64.dll
        encrypt-arm.dll
        encrypt-arm64.dll

Ontwikkelaars kunnen vervolgens tijdens runtime LoadLibrary("bin\encrypt-" + cpu + ".dll") uitvoeren om het juiste binaire bestand voor hun proces op te halen.

Normaal gesproken hebben neutrale pakketten geen inhoud per architectuur, maar dat kan wel. Er zijn limieten voor wat u kunt doen (u kunt bijvoorbeeld een Kladblok-pakket maken met notepad.exe gecompileerd voor x86 + x64 + arm + arm64, maar appxmanifest.xml kan alleen <Application Executable=...> verwijzen naar een van hen declareren). Aangezien er bundels zijn waarmee u alleen de benodigde bits kunt installeren, is dit een zeer ongebruikelijke taak. Het is niet illegaal, alleen geavanceerd en exotisch.

Bovendien betekent Architecture=x86 (of x64|arm|arm64) niet dat het pakket alleen uitvoerbare code bevat voor de opgegeven architectuur. Het is gewoon de overweldigende gangbare zaak.

Opmerking

Wanneer we in deze context 'code' of 'uitvoerbare code' bespreken, verwijzen we naar PE-bestanden (portable executable).

Is pakketidentiteit hoofdlettergevoelig?

Over het algemeen niet, maar Publisher is hoofdlettergevoelig.

De resterende velden (Name, ResourceId, PublisherId, PackageFullName en PackageFamilyName) zijn dat niet. Deze velden behouden hoofdlettergebruik, maar vergelijken hoofdletterongevoelig.

Zie ook

pakketidentiteit

PackageFamilyNameFromId-

PakketNaamEnUitgeverIdVanFamilieNaam