Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Ein funktionierendes End-to-End-Beispiel (WPF App + Inno Setup-Installationsprogramm) finden Sie im Beispiel "sparse-app".
Eine standardmäßige ausführbare Desktopdatei , die mit dotnet buildMSBuild, CMake oder einer anderen Toolkette erstellt wurde, weist keine Paketidentität auf. Ohne Identität kann es nicht viele moderne Windows-APIs (Popupbenachrichtigungen, Hintergrundaufgaben, Freigabeziele, Startaufgaben, App-Daten-APIs und mehr) verwenden.
Sparse-Paketierung verleiht einer App eine Identität, ohne ihre Binärdateien in ein MSIX-Paket zu verschieben. Sie liefern nur eine winzige reine Identität.msix (nur ein Manifest), und registrieren sie zusammen mit Ihrer normal installierten App an einem externen Speicherort. Ihr .exe Bleibt genau dort, wo ihr Installationsprogramm es platziert. Dies ist das Gegenstück für die Produktionsumgebung zu winapp create-debug-identity, das nur zum Debugging während der Entwicklung dient.
In diesem Leitfaden werden die drei CLI-Schritte behandelt, die den ersten drei Schritten des offiziellen Genehmigungsidentitätsworkflows für nicht verpackte Apps zugeordnet sind:
| Schritt | Befehl | Result |
|---|---|---|
| 1. Erstellen des Identitätsmanifests | winapp init --exe <exe> --sparse |
sparse/appxmanifest.xml + sparse/Assets/ |
| 2. Erstellen und Signieren des Identitätspakets | winapp pack <appxmanifest.xml> --cert <pfx> |
<PackageName>.identity.msix |
| 3. Einbetten der Identität in die App | winapp embed-identity <exe> |
<msix> Element im Fusionsmanifest der Exe |
Die Schritte 4 bis 5 der Dokumente (Registrieren/Aufheben der Registrierung des Pakets) sind die Verantwortung Ihres Installers – siehe Installationsprogrammintegration.
Gründe für die Verwendung von sparsamen Verpackungen
- Sie verfügen bereits über ein ausgereiftes Installationsprogramm (Inno Setup, WiX, NSIS, MSI) und möchten nicht zur Verteilung zu MSIX wechseln, sie benötigen jedoch identitätsgesteuerte Windows APIs.
- Ihre App muss auf einem Pfad oder mit einem Layout installieren, das MSIX nicht zulässt.
- Sie möchten eine minimale, additive Änderung: Halten Sie ihren vorhandenen Installationsablauf, und fügen Sie einen
.msixRegistrierungsschritt hinzu.
Wenn Sie neu beginnen und als MSIX verteilen können, ist eine vollständige verpackte App (winapp init + winapp pack <folder>) einfacher.
Voraussetzungen
- Windows 10, Version 2004 (Build 19041) oder höher. Sparsepakete basieren auf
uap10:AllowExternalContent, wofür 19041+ erforderlich ist. -
winapp CLI — über winget installieren (oder aktualisieren, falls bereits installiert):
winget install Microsoft.WinApp --source winget - Ein auf dem Zielcomputer vertrauenswürdiges Codesignaturzertifikat. Generieren Sie für lokale Tests mit
winapp cert generateein Entwicklungszertifikat und vertrauen Sie ihm. Produktionspakete müssen mit einem Zertifikat signiert werden, dessen Betreff dem ManifestPublisherentspricht.
Walkthrough
In den folgenden Beispielen wird davon ausgegangen, dass unter ./bin/Release/net8.0-windows/MyApp.exe eine kompilierte ausführbare Datei vorliegt.
Schritt 1 — Erstellen Sie das spärliche Identitätsmanifest
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse
Dadurch wird der Paketname, der Herausgeber, die Version und die Beschreibung aus der Exe (über die Dateiversionsinformationen) abgeleitet und Sie aufgefordert, sie zu akzeptieren oder zu überschreiben. Fügen Sie --use-defaults (oder --no-prompt) hinzu, um die Eingabeaufforderungen in CI zu überspringen und --name / --publisher bestimmte Werte außer Kraft zu setzen:
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse --use-defaults `
--name "Contoso.MyApp" --publisher "CN=Contoso"
Standardmäßig schreibt es Folgendes in einen eigenen sparse/-Ordner im aktuellen Verzeichnis (kann mit --output-dir überschrieben werden):
-
appxmanifest.xml— ein minimales Manifest mit<uap10:AllowExternalContent>true</uap10:AllowExternalContent>(einem Element unter<Properties>),ProcessorArchitecture="neutral", einerwin32App-Anwendung und dem inExecutableeingetragenen EXE-Namen. -
Assets/– visuelle Platzhalterressourcen (die nach Möglichkeit aus dem Symbol der EXE-Datei extrahiert werden).
Warum ein
sparse/Ordner und nicht neben der exe? Das Manifest undAssets/sind Eingaben zur Buildzeit, die vonwinapp packundwinapp embed-identityverwendet werden — nichts liest sie zur Laufzeit neben der EXE ein (die Laufzeitidentität ergibt sich aus dem in die EXE eingebetteten<msix>-Element sowie dem externen Speicherort des registrierten Pakets, und das Manifest verweist anhand des Namens auf die EXE, sodass sein Speicherort unabhängig davon ist, wo sich die EXE befindet). Wenn Sie sie in einen eigenen, versionsverwalteten Ordner schreiben, bleiben sie außerhalb eines Build-Ausgabeverzeichnisses (wiebin/), das bei einem Clean/Rebuild gelöscht würde, und der Ordner bleibt frei von Binärdateien, sodass die nächsten Schritte sauber bleiben.winapp packundwinapp embed-identitydurchsuchensparse/automatisch, sodass Sie den Pfad nur selten angeben müssen.
Hinweis: Der spärliche Init-Fluss überspringt absichtlich alle SDK-/Paketinstallationen – Identitätspakete weisen keine SDK-Abhängigkeiten auf.
Wenn im Zielverzeichnis bereits eine appxmanifest.xml vorhanden ist, wird die Initialisierung angehalten, anstatt sie (und ihre Assets/) zu überschreiben. Führen Sie den Befehl mit --force erneut aus, um es neu zu generieren.
Stellen Sie sicher, dass das im generierten Manifest enthaltene Publisher mit dem Zertifikat übereinstimmt, das Sie zum Signieren verwenden. Bearbeiten Sie --publisher bei Bedarf oder übergeben Sie appxmanifest.xml beim Generieren.
Schritt 2 – Erstellen und Signieren des Identitätspakets
Verweisen Sie winapp pack auf das Sparse-Manifest (eine Datei, kein Ordner):
winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx
Da das Manifest AllowExternalContentdeklariert, erstellt ein .msixwinapp pack-Paket, das nur das Manifest enthält – keine Binärdateien, keine Ressourcen. Die Ausgabe wird standardmäßig in <PackageName>.identity.msix im aktuellen Verzeichnis gespeichert; verwenden Sie --output, um dies zu ändern. Die Signierung erfolgt nur, wenn Sie --cert (oder --generate-cert) übergeben.
Schritt 3 – Einbetten der Identität in Ihre App
Betten Sie das <msix> Element ein, damit Windows die ausgeführte exe mit dem Identitätspaket verbindet:
# EXE mode — modify the built binary in place (uses mt.exe)
winapp embed-identity ./bin/Release/net8.0-windows/MyApp.exe
Oder behalten Sie die parallele Manifestdatei als eingecheckte Datei bei, und erstellen Sie sie neu:
# XML mode — update an external SxS manifest, then rebuild your app
winapp embed-identity ./app.manifest
Im XML-Modus wird das <msix> Element in das Zielmanifest eingefügt (oder ersetzt). Verweisen Sie auf dieses Manifest aus Ihrem Projekt (für .NET, festlegen<ApplicationManifest>app.manifest</ApplicationManifest>), und erstellen Sie es neu, damit das Element in die exe eingebettet ist.
Beide Modi lesen die Identität aus einer Sparse-appxmanifest.xml. Wenn Sie --manifest weglassen, sucht winapp zuerst in einem sparse/-Ordner neben dem Ziel (in den winapp init --exe --sparse sie standardmäßig schreibt), dann im aktuellen Verzeichnis und greift schließlich auf den Pfad neben dem Ziel und das aktuelle Verzeichnis zurück. Übergeben Sie --manifest, um auf einen anderen Speicherort zu verweisen.
Hinweis: Im EXE-Modus wird die Binärdatei mit
mt.exeneu geschrieben, wodurch jede vorhandene Authenticode-Signatur ungültig wird. Signieren Sie die exe (z.B.winapp sign ./MyApp.exe <cert.pfx>) vor der Verteilung erneut.
Schritt 4 – Registrieren (für lokale Tests)
Die Logos des Manifests werden zur Laufzeit über den externen Speicherort aufgelöst, nicht über die reine Identitäts-.msix. Schritt 1 hat sie unter ./sparse/Assets abgelegt, also kopieren Sie sie vor der Registrierung neben Ihre EXE-Datei (also an den externen Speicherort) — andernfalls registriert Windows ein Layout, dem alle Logos fehlen, auf die im Manifest verwiesen wird:
# Copy the generated assets into the external location (beside your exe)
Copy-Item ./sparse/Assets -Destination .\bin\Release\net8.0-windows\Assets -Recurse -Force
Registrieren Sie dann das Identitätspaket für diesen Ordner (den externen Speicherort):
Add-AppxPackage -Path .\MyApp.identity.msix `
-ExternalLocation (Resolve-Path .\bin\Release\net8.0-windows)
Starten Sie die App, und vergewissern Sie sich, dass eine Identität vorhanden ist, zum Beispiel sollte Windows.ApplicationModel.Package.Current.Id.FamilyName Ihren Paketfamiliennamen zurückgeben, anstatt einen Fehler auszulösen.
Zum Bereinigen:
Remove-AppxPackage <full-package-name>
Asset-Verwaltung
Die Sparse .msix ist nur identitätsbasiert. Die im Manifest referenzierten visuellen Ressourcen (Assets\StoreLogo.png, Kacheln usw.) werden zur Laufzeit aus dem externen Inhaltsspeicherort aufgelöst — d. h. aus dem Installationsverzeichnis Ihrer App — nicht aus dem Inneren des .msix.
Dies bedeutet, dass Sie den Assets/ Ordner zusammen mit Ihrer Anwendung bereitstellen müssen (dasselbe Layout, das das Manifest erwartet, relativ zum externen Speicherort).
Schritt 2 verpackt die Datei mit dem Manifest direkt (winapp pack ./sparse/appxmanifest.xml), wodurch die rein identitätsbasierte .msix nur aus diesem Manifest erstellt wird – Dateien im selben Verzeichnis werden ignoriert, sodass es Ihre Assets oder Binärdateien nie enthält. (Wenn Sie stattdessen mit auf einen winapp pack verweisen, dessen Manifest AllowExternalContent deklariert, warnt es vor allen Ressourcen oder Binärdateien, die es findet, da diese bei einem Sparsepaket an den externen Speicherort gehören und nicht in das .msix.)
Installer-Integration
Registrierung und Deregistrierung sind Aufgabe des Installationsprogramms. Das Muster ist für alle Installationstools identisch:
-
Installieren: Kopieren Sie die App-Binärdateien, den
Assets/-Ordner und.msixin das Installationsverzeichnis und führen Sie dannAdd-AppxPackage -Path "<install-dir>\MyApp.identity.msix" -ExternalLocation "<install-dir>"aus. -
Deinstallieren: Vor dem Löschen von Dateien ausführen
Remove-AppxPackage <full-package-name>.
Sicherheit: Das Installationsverzeichnis wird zur Installationszeit aufgelöst und kann Zeichen (z. B. ein einzelnes Anführungszeichen) enthalten, die ein PowerShell-Zeichenfolgenliteral verlassen. Escapen oder validieren Sie den Pfad stets, bevor Sie ihn in eine
-Command-Zeichenfolge interpolieren. Die folgenden WiX- und NSIS-Codeausschnitte gehen von einem vertrauenswürdigen Installationspfad aus, während das „Inno Setup“-Beispiel sicheres Escaping demonstriert. Übergeben Sie Pfade vorzugsweise als Argumente an ein-File-Skript, anstatt die Inline--Command-Interpolation zu verwenden.
Inno Setup
Erstellen Sie die PowerShell-Argumente in einer [Code]-Funktion, sodass der Installationspfad der Runtime für das in einfache Anführungszeichen gesetzte PowerShell-Literal per Escape maskiert wird (ein Installationsverzeichnis, das ein ' enthält, darf kein Skript einfügen können):
[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;
Sehen Sie sich das Beispiel für sparse-app an, um ein vollständiges, funktionierendes Beispiel zu finden setup.iss.
Die folgenden WiX- und NSIS-Beispiele rufen über -File ein kleines register-sparse.ps1 auf, sodass der Installationspfad als Parameter übergeben wird (PowerShell bindet ihn als Daten), anstatt in einen -Command-String interpoliert zu werden. Dadurch wird die Skripteinfügung über ein gestaltetes Installationsverzeichnis vermieden (z. B. ein Ordnername mit einem Anführungszeichen oder $(...)):
# 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)
Registrieren Sie pro Benutzer (Impersonate="yes"), da Add-AppxPackage das Paket für das Konto registriert, unter dem es ausgeführt wird. Eine verzögerte Aktion mit Impersonate="no" wird als LocalSystem ausgeführt, was dem installierenden Benutzer keine Identität verleiht (und häufig abgelehnt wird). Führen Sie die Registrierung für eine computerbezogene MSI-Datei mit Identitätswechsel aus, damit sie für den aufrufenden Benutzer gilt.
Eine verzögerte benutzerdefinierte Aktion kann nicht direkt gelesen INSTALLFOLDER werden (verzögerte Aktionen werden in einem Kontext ohne Zugriff auf Eigenschaften ausgeführt), und durch einfaches Deklarieren der Aktion wird sie nicht ausgeführt. Marshallen Sie also die Pfade über CustomActionData – eine sofortige Aktion vom Typ 51, deren Property-Name der Id der verzögerten Aktion entspricht –, und planen Sie beide nach InstallFiles ein:
<!-- 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 ist in der WiX-Util-Erweiterung (WixUtilExtension) enthalten; verweisen Sie auf sie, damit die WixCA-Binärdatei verfügbar ist.
Eine einzelne imitierte Aktion registriert die Identität nur für den Benutzer, der das Installationsprogramm ausführt. Um jeden Benutzer einer computerbezogenen Installation bereitzustellen, führen Sie die Registrierung stattdessen beim ersten Start (pro Benutzer) durch, oder verwenden Sie einen Bereitstellungsmechanismus wie
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
Troubleshooting
Package.Current gibt zur Laufzeit / "keine Paketidentität" aus
- Das Identitätspaket ist nicht registriert, oder im Fusion-Manifest der EXE-Datei fehlt das Element
<msix>. Führen Sie die Datei erneut aus (und erstellen Sie sie erneut, wenn sie den XML-Moduswinapp embed-identityverwenden), und registrieren Sie sich dann erneut beiAdd-AppxPackage -ExternalLocation. - Die
<msix packageName>/ /publisherapplicationIdin der Exe muss genau mit der Identität des registrierten Pakets übereinstimmen.
Objekte/Logos werden nicht angezeigt
- Stellen Sie sicher, dass der
Assets/Ordner am externen Speicherort mit denselben relativen Pfaden bereitgestellt wird, die das Manifest erwartet. Ressourcen werden über den externen Speicherort aufgelöst, nicht über die.msix.
Add-AppxPackage schlägt mit einem Signatur- oder Vertrauensfehler fehl
- Das
.msixMuss von einem Zertifikat signiert werden, das auf dem Computer vertrauenswürdig ist und dessen Betreff mit dem ManifestPublisherübereinstimmt. Generieren und vertrauen Sie für lokale Tests ein Dev-Zertifikat mitwinapp cert generate, und stellen Sie sicher, dass das Manifest mit dem ZertifikatPublisherübereinstimmt.
MakeAppx: "Anwendung mit dem RuntimeBehavior-Wert 'win32App' darf keinen EntryPoint deklarieren"
- Eine Sparse-
win32App-Anwendung darfEntryPointnicht deklarieren. Von ihnen generiertewinapp init --sparseManifeste sind bereits korrekt. Entfernen Sie jedesEntryPointAttribut, wenn Sie das Manifest manuell bearbeitet haben.
"Die Eingabe ist eine Datei, aber kein Sparse-Manifest"
-
winapp pack <file>akzeptiert nur ein Manifest, in dem<uap10:AllowExternalContent>true</uap10:AllowExternalContent>angegeben ist. Generieren Sie einen mitwinapp init --exe <exe> --sparse, oder übergeben Sie einen Eingabeordner , um einen vollständigen MSIX zu erstellen.
Siehe auch
Windows developer