Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Zie het voorbeeld van de sparse-app voor een werkend end-to-end-voorbeeld (WPF app + Installatie-installatieprogramma voor Inno).
Een standaard uitvoerbaar bureaublad, gebouwd met dotnet build, MSBuild, CMake of een andere toolchain, heeft geen pakketidentiteit. Zonder identiteit kunnen er geen moderne Windows API's worden gebruikt (pop-upmeldingen, achtergrondtaken, doelen delen, opstarttaken, api's voor app-gegevens en meer).
Sparse packaging verleent identiteit aan een app zonder de binaire bestanden naar een MSIX te verplaatsen. U verzendt een kleine identiteit.msix (alleen een manifest) en registreert deze naast uw normaal geïnstalleerde app met behulp van een externe locatie. Je .exe blijft precies waar je installateur het plaatst. Dit is de productievariant van winapp create-debug-identity, die uitsluitend bedoeld is voor debuggen tijdens de ontwikkeling.
In deze handleiding worden de drie CLI-stappen behandeld die overeenkomen met de eerste drie stappen van de officiële workflow Een identiteit toekennen aan niet-verpakte apps:
| Stap | Command | Result |
|---|---|---|
| 1. Het identiteitsmanifest maken | winapp init --exe <exe> --sparse |
sparse/appxmanifest.xml + sparse/Assets/ |
| 2. Het identiteitspakket bouwen en ondertekenen | winapp pack <appxmanifest.xml> --cert <pfx> |
<PackageName>.identity.msix |
| 3. Identiteit insluiten in de app | winapp embed-identity <exe> |
<msix> element in het samenvoegingsmanifest van de exe |
Stap 4-5 van de documenten (registreren/de registratie van het pakket ongedaan maken) zijn de verantwoordelijkheid van uw installatieprogramma . Zie De integratie van het installatieprogramma.
Wanneer sparse verpakking te gebruiken
- U hebt al een volwassen installatieprogramma (Inno Setup, WiX, NSIS, MSI) en wilt niet overschakelen naar MSIX voor distributie, maar u hebt id-gated Windows API's nodig.
- Uw app moet worden geïnstalleerd op een pad of met een indeling die MSIX niet toestaat.
- U wilt een minimale, additieve wijziging: behoud uw bestaande installatiestroom en voeg één
.msixregistratiestap toe.
Als u nieuw begint en als MSIX kunt distribueren, is een volledige verpakte app (winapp init + winapp pack <folder>) eenvoudiger.
Prerequisites
- Windows 10 versie 2004 (build 19041) of hoger. Sparse-pakketten zijn afhankelijk van
uap10:AllowExternalContent, dat 19041+ vereist. -
winapp CLI : installeren via winget (of bijwerken als deze al is geïnstalleerd):
winget install Microsoft.WinApp --source winget -
Een certificaat voor ondertekening van programmacode dat wordt vertrouwd op de doelcomputer. Voor lokale tests genereert u een ontwikkelingscertificaat met
winapp cert generateen vertrouwt u het. Productiepakketten moeten worden ondertekend met een certificaat waarvan het onderwerp overeenkomt met het manifestPublisher.
Walkthrough
In de onderstaande voorbeelden wordt ervan uitgegaan dat er een ingebouwd uitvoerbaar bestand is op ./bin/Release/net8.0-windows/MyApp.exe.
Stap 1: het sparse-identiteitsmanifest maken
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse
Hiermee wordt de pakketnaam, uitgever, versie en beschrijving van de exe afgeleid (via de informatie over de bestandsversie) en wordt u gevraagd deze te accepteren of te negeren. Voeg --use-defaults (of --no-prompt) toe om de prompts in CI over te slaan en --name / --publisher om specifieke waarden te overschrijven:
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse --use-defaults `
--name "Contoso.MyApp" --publisher "CN=Contoso"
Het schrijft standaard het volgende naar een toegewezen sparse/ map in de huidige map (overschrijven met --output-dir):
-
appxmanifest.xml— een sparse manifest met<uap10:AllowExternalContent>true</uap10:AllowExternalContent>(een element onder<Properties>),ProcessorArchitecture="neutral", eenwin32Apptoepassing, en de exe-naam ingevuld inExecutable. -
Assets/— tijdelijke visuele elementen (indien mogelijk geëxtraheerd uit het pictogram van het EXE-bestand).
Waarom een
sparse/map en niet naast de exe? Het manifest enAssets/zijn buildtime-invoer die wordt gebruikt doorwinapp packenwinapp embed-identity: er wordt niets gelezen van naast de exe tijdens runtime (runtime-identiteit komt van het<msix>element dat is ingesloten in de exe plus de externe locatie van het geregistreerde pakket, en het manifest verwijst naar de exe op naam, dus de locatie is onafhankelijk van waar de exe zich bevindt). Door ze in een aparte map onder versiebeheer te schrijven, blijven ze buiten een build-uitvoermap (zoalsbin/) die door een clean/rebuild-actie zou worden gewist, en blijft de map vrij van binaire bestanden zodat de volgende stappen schoon verlopen.winapp packenwinapp embed-identitykijken automatisch insparse/, dus u hoeft het pad zelden op te geven.
Opmerking: De sparse init-stroom slaat bewust alle SDK-/pakketinstallatie over . Identiteitspakketten hebben geen SDK-afhankelijkheden.
Als er al een appxmanifest.xml bestaat in de doelmap, stopt init in plaats van deze te overschrijven (en de bijbehorende Assets/). Voer het opnieuw uit met --force om het opnieuw te genereren.
Zorg ervoor dat de Publisher in het gegenereerde manifest overeenkomt met het certificaat waarmee u ondertekent. Bewerk appxmanifest.xml indien nodig, of geef --publisher door tijdens het genereren.
Stap 2: het identiteitspakket bouwen en ondertekenen
Wijs winapp pack het sparse-manifest aan (een bestand, geen map):
winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx
Omdat het manifest AllowExternalContent vermeldt, bouwt winapp pack een pakket dat alleen uit een identiteit bestaat.msix en alleen het manifest bevat — geen binaire bestanden, geen resources. De uitvoer is standaard <PackageName>.identity.msix in de huidige map; gebruik --output om dit te wijzigen. Ondertekening vindt alleen plaats wanneer u doorgeeft --cert (of --generate-cert).
Stap 3: identiteit insluiten in uw app
Sluit het <msix> element in, zodat Windows de actieve exe verbindt met het identiteitspakket:
# EXE mode — modify the built binary in place (uses mt.exe)
winapp embed-identity ./bin/Release/net8.0-windows/MyApp.exe
Of behoud het side-by-side-manifest als een in versiebeheer opgenomen bestand en voer vervolgens een nieuwe build uit:
# XML mode — update an external SxS manifest, then rebuild your app
winapp embed-identity ./app.manifest
In de XML-modus wordt het <msix> element in het doelmanifest ingevoegd (of vervangen). Verwijs naar het manifest van uw project (voor .NET, stel het in<ApplicationManifest>app.manifest</ApplicationManifest>) en bouw het opnieuw, zodat het element is ingesloten in de exe.
Beide modi lezen de identiteit van een sparse appxmanifest.xml. Wanneer u --manifest weglaat, zoekt winapp eerst in een sparse/-folder (waar winapp init --exe --sparse deze standaard naartoe schrijft) naast het doelbestand, daarna in de huidige map, en valt daarna terug op het doelbestand en de huidige map; gebruik --manifest om een andere locatie op te geven.
Opmerking: De EXE-modus herschrijft het binaire bestand met
mt.exe, waarmee een bestaande Authenticode-handtekening ongeldig wordt gemaakt. Onderteken de exe (bijvoorbeeldwinapp sign ./MyApp.exe <cert.pfx>) opnieuw voordat u het distribueert.
Stap 4: registreren (voor lokaal testen)
De logo's van het manifest worden tijdens de runtime opgehaald van de externe locatie, niet vanuit de uitsluitend voor identiteit bedoelde .msix. Stap 1 heeft ze onder ./sparse/Assets geplaatst, dus kopieer ze naast uw .exe-bestand (de externe locatie) voordat u deze registreert — anders registreert Windows een toetsenbordindeling waarin alle logo's ontbreken waarnaar in het manifest wordt verwezen:
# Copy the generated assets into the external location (beside your exe)
Copy-Item ./sparse/Assets -Destination .\bin\Release\net8.0-windows\Assets -Recurse -Force
Registreer vervolgens het identiteitspakket voor die map (de externe locatie):
Add-AppxPackage -Path .\MyApp.identity.msix `
-ExternalLocation (Resolve-Path .\bin\Release\net8.0-windows)
Start de app en bevestig dat de identiteit aanwezig is. U moet bijvoorbeeld Windows.ApplicationModel.Package.Current.Id.FamilyName de familienaam van uw pakket retourneren in plaats van te gooien.
Op te schonen:
Remove-AppxPackage <full-package-name>
Afhandeling van activa
De sparse .msix is uitsluitend identiteit. De visuele resources waarnaar in het manifest wordt verwezen (Assets\StoreLogo.png, tegels, enz.) worden tijdens runtime opgehaald uit de externe inhoudslocatie — dat wil zeggen: uit de installatiemap van uw app — niet vanuit de .msix zelf.
Dit betekent dat u de Assets/ map naast uw toepassing moet implementeren (dezelfde indeling die het manifest verwacht ten opzichte van de externe locatie).
Stap 2 verpakt het manifestbestand rechtstreeks (winapp pack ./sparse/appxmanifest.xml), waarbij de alleen-identiteit-.msix uitsluitend op basis van dat manifest wordt opgebouwd — naastgelegen bestanden worden genegeerd, dus je resources of binaire bestanden worden nooit opgenomen. (Als u winapp pack in plaats daarvan naar een map laat verwijzen waarvan het manifest AllowExternalContent vermeldt, waarschuwt het voor alle resources of binaire bestanden die het aantreft, omdat die bij een sparse-pakket op de externe locatie thuishoren en niet in de .msix.)
Installatieprogramma-integratie
Registratie en niet-registratie zijn de taak van het installatieprogramma. Het patroon is hetzelfde voor installatieprogramma's:
-
Installeren: kopieer de binaire bestanden van uw app, de
Assets/map en de.msixmap naar de installatiemap en voer vervolgens uitAdd-AppxPackage -Path "<install-dir>\MyApp.identity.msix" -ExternalLocation "<install-dir>". -
Verwijderen: uitvoeren
Remove-AppxPackage <full-package-name>voordat u bestanden verwijdert.
Beveiliging: de installatiemap wordt opgelost tijdens de installatie en kan tekens (bijvoorbeeld één aanhalingsteken) bevatten die uit een letterlijke PowerShell-tekenreeks uitbreken. Escape of valideer het pad altijd voordat u het in een
-Command-tekenreeks interpoleert — de onderstaande WiX- en NSIS-fragmenten gaan uit van een vertrouwd installatiepad, terwijl het Inno Setup-voorbeeld laat zien hoe u veilig kunt escapen. Geef paden bij voorkeur door als argumenten aan een-File-script, in plaats van via inline--Command-interpolatie.
Installatie van Inno
Bouw de PowerShell-argumenten op in een [Code] functie, zodat het installatiepad van de runtime correct wordt ge-escaped voor de PowerShell-letterlijke tekenreeks tussen enkele aanhalingstekens (een installatiemap die een ' bevat, mag geen scriptinjectie mogelijk maken):
[Files]
Source: "dist\*"; DestDir: "{app}"; Flags: recursesubdirs
Source: "MyApp.identity.msix"; DestDir: "{app}"
[Run]
Filename: "powershell.exe"; Parameters: "{code:RegisterParams}"; Flags: runhidden
[UninstallRun]
Filename: "powershell.exe"; \
Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Get-AppxPackage -Name 'MyApp' | Remove-AppxPackage"""; \
Flags: runhidden
[Code]
function EscapePSLiteral(const Value: string): string;
var S: string;
begin
S := Value; StringChange(S, '''', ''''''); Result := S;
end;
function RegisterParams(Param: string): string;
var AppDir: string;
begin
AppDir := ExpandConstant('{app}');
{ -ErrorAction Stop + try/catch make a registration failure terminating, so powershell.exe
exits nonzero and the AfterInstall callback (see the full sample) can abort with rollback. }
Result := '-NoProfile -ExecutionPolicy Bypass -Command "try { Add-AppxPackage -Path ''' +
EscapePSLiteral(AppDir + '\MyApp.identity.msix') +
''' -ExternalLocation ''' + EscapePSLiteral(AppDir) + ''' -ErrorAction Stop } catch { Write-Error $_; exit 1 }"';
end;
Zie het sparse-app-voorbeeld voor een volledig, werkend setup.iss.
De onderstaande WiX- en NSIS-voorbeelden roepen via -File een kleine register-sparse.ps1 aan, waarbij het installatiepad als een parameter wordt doorgegeven (PowerShell bindt die als gegevens) in plaats van in een -Command-tekenreeks te worden geïnterpoleerd. Dit voorkomt scriptinjectie via een gemaakte installatiemap (bijvoorbeeld een mapnaam met een aanhalingsteken of $(...)):
# register-sparse.ps1 — ship this alongside your installer
param(
[Parameter(Mandatory)] [string] $MsixPath,
[Parameter(Mandatory)] [string] $ExternalLocation,
[Parameter(Mandatory)] [string] $PackageName
)
$ErrorActionPreference = 'Stop'
try {
# Add-AppxPackage emits NON-terminating errors by default, so a failure would otherwise leave
# the process exit code at 0 and let the installer complete without identity. Try the add
# directly first: a fresh install or a version-bumped upgrade registers/updates in place
# without touching any existing registration. -ErrorAction Stop + the outer trap make a real
# failure terminating so the installer (WiX Return="check" / NSIS) sees it.
try {
Add-AppxPackage -Path $MsixPath -ExternalLocation $ExternalLocation -ErrorAction Stop
} catch {
# Only ONE failure is safe to resolve by unregister+retry: the exact same version is already
# registered (HRESULT 0x80073CFB, ERROR_PACKAGE_ALREADY_EXISTS — "already installed,
# reinstallation blocked"), which Add-AppxPackage rejects. Re-throw everything else
# (untrusted/corrupt .msix, unsupported OS, ...) so a bad new package can NEVER unregister a
# working prior registration and strip the installed app of the identity it already had.
if ($_.Exception.HResult -ne 0x80073CFB) { throw }
Get-AppxPackage -Name $PackageName | Remove-AppxPackage -ErrorAction SilentlyContinue
Add-AppxPackage -Path $MsixPath -ExternalLocation $ExternalLocation -ErrorAction Stop
}
} catch {
Write-Error $_
exit 1
}
WiX (v3)
Registratie per gebruiker (Impersonate="yes"), omdat Add-AppxPackage het pakket registreert voor het account waaronder het wordt uitgevoerd. Een uitgestelde actie met Impersonate="no" wordt uitgevoerd als LocalSystem, wat de gebruiker die de installatie uitvoert geen identiteit toekent (en doorgaans wordt afgewezen). Voer voor een MSI per machine de registratie uit die is geïmiteerd, zodat deze van toepassing is op de aanroepende gebruiker.
Een uitgestelde aangepaste actie kan INSTALLFOLDER niet rechtstreeks lezen (uitgestelde acties worden uitgevoerd in een context zonder toegang tot eigenschappen), en alleen het declareren van de actie voert deze niet uit. Dus leid de paden via CustomActionData — een onmiddellijke actie van type 51 waarvan Property dezelfde naam heeft als de uitgestelde actie Id — en plan beide na InstallFiles:
<!-- Immediate: stash the command line (with the resolved paths) into the deferred action's
CustomActionData. Windows Installer copies the value of the property named the same as a
deferred action into that action's CustomActionData. -->
<CustomAction Id="SetRegisterSparseCmd" Property="RegisterSparse" Execute="immediate"
Value="powershell.exe -NoProfile -ExecutionPolicy Bypass -File "[INSTALLFOLDER]register-sparse.ps1" -MsixPath "[INSTALLFOLDER]MyApp.identity.msix" -ExternalLocation "[INSTALLFOLDER]" -PackageName "MyPackageIdentityName"" />
<!-- Deferred + impersonated: CAQuietExec reads its command line from CustomActionData when run
deferred, so it registers the package for the invoking user. Return="check" fails the
install if registration fails. -->
<CustomAction Id="RegisterSparse" BinaryKey="WixCA" DllEntry="CAQuietExec"
Execute="deferred" Impersonate="yes" Return="check" />
<InstallExecuteSequence>
<Custom Action="SetRegisterSparseCmd" After="InstallFiles">NOT Installed</Custom>
<Custom Action="RegisterSparse" After="SetRegisterSparseCmd">NOT Installed</Custom>
</InstallExecuteSequence>
CAQuietExec is opgenomen in de WiX util-extensie (WixUtilExtension); neem er een verwijzing naar op zodat het binaire bestand WixCA beschikbaar is.
Met één geïmiteerde actie wordt alleen de identiteit geregistreerd voor de gebruiker die het installatieprogramma uitvoert. Om elke gebruiker van een systeembrede installatie in te richten, registreert u deze in plaats daarvan bij de eerste keer opstarten (per gebruiker) of gebruikt u een inrichtingsmechanisme zoals
Add-AppxProvisionedPackage.
NSIS
Section
# Capture the PowerShell exit code and abort if registration failed. register-sparse.ps1 exits
# nonzero on failure (it sets $ErrorActionPreference='Stop' and traps), so without this check the
# installer would complete even though the app has no identity.
ExecWait 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\register-sparse.ps1" -MsixPath "$INSTDIR\MyApp.identity.msix" -ExternalLocation "$INSTDIR" -PackageName "MyPackageIdentityName"' $0
IntCmp $0 0 +2
Abort "Registering the sparse identity package failed (exit code $0). The app requires package identity."
SectionEnd
Problemen oplossen
Package.Current genereert / 'geen pakketidentiteit' tijdens runtime
- Het identiteitspakket is niet geregistreerd of het samenvoegingsmanifest van de exe ontbreekt in het
<msix>element. Voer opnieuw uitwinapp embed-identity(en bouw opnieuw als u de XML-modus gebruikt) en registreer u vervolgens opnieuw bijAdd-AppxPackage -ExternalLocation. - De
<msix packageName>/ /publisherapplicationIdin de exe moet exact overeenkomen met de identiteit van het geregistreerde pakket.
Assets en logo’s worden niet weergegeven
- Zorg ervoor dat de
Assets/map op de externe locatie wordt geïmplementeerd met dezelfde relatieve paden die het manifest verwacht. Assets worden omgezet vanaf de externe locatie, niet de.msix.
Add-AppxPackage mislukt vanwege een ondertekenings- of vertrouwensfout
- Het
.msixmoet worden ondertekend door een certificaat dat wordt vertrouwd op de computer en waarvan het onderwerp overeenkomt met het manifestPublisher. Voor lokale tests genereert en vertrouwt u een dev-certificaat metwinapp cert generateen zorgt u ervoor dat het manifest overeenkomt met het certificaatPublisher.
MakeAppx: "Toepassing met RuntimeBehavior-waarde 'win32App' mag geen EntryPoint declareren"
- Een sparse-toepassing
win32AppmagEntryPointniet declareren. Manifesten die zijn gegenereerd doorwinapp init --sparsezijn al correct; verwijder het kenmerkEntryPointals u het manifest handmatig hebt bewerkt.
"Invoer is een bestand maar geen sparse-manifest"
-
winapp pack <file>accepteert alleen een manifest dat declareert<uap10:AllowExternalContent>true</uap10:AllowExternalContent>. Genereer er een metwinapp init --exe <exe> --sparseof geef een invoermap door om een volledige MSIX te bouwen.
Zie ook
Windows developer