Microsoft dokumentiert, was das Package Support Framework ist. Viel schwerer zu finden ist das, was Sie donnerstags um 16 Uhr wirklich brauchen: Die Anwendung wurde sauber paketiert, sie installiert sich, sie startet, und dann macht sie etwas falsch. Welches Fixup heilt welches Symptom?

Das ist genau diese Zuordnung. Sie setzt voraus, dass das Paket selbst gültig ist und das Problem im Verhalten liegt.

Was PSF tatsächlich tut

Das Package Support Framework sitzt zwischen einer paketierten Anwendung und Windows und fängt Aufrufe ab, die die Anwendung macht. MSIX führt Anwendungen in einem Container mit umgeleiteten Datei- und Registry-Schreibvorgängen aus, und mit einem Arbeitsverzeichnis, das nicht immer das ist, was die Anwendung angenommen hat. Ältere Anwendungen wurden geschrieben, bevor es all das gab, also fragen sie Dinge auf eine Weise an, die der Container anders beantwortet.

Mechanisch sind es drei Teile. PSFLauncher32.exe oder PSFLauncher64.exe ersetzt Ihre Anwendung als Executable-Attribut des Application-Elements im Manifest, sodass er zuerst läuft. Er liest config.json aus dem Wurzelverzeichnis des Pakets. Anschließend injiziert er die PSF-Laufzeit und die von Ihnen benannten Fixup-DLLs in den Anwendungsprozess, und die Anwendung startet dahinter. Wenn Sie sich der Architektur der Anwendung nicht sicher sind, funktioniert der 32-Bit-Launcher in jedem Fall.

Wie das Package Support Framework in einem MSIX-Paket sitzt. Die Windows-Shell startet PSFLauncher, der config dot json aus dem Paketwurzelverzeichnis liest. Diese Datei deklariert die Anwendungs-ID, den echten Pfad zur ausführbaren Datei, ein optionales Arbeitsverzeichnis und die zu ladenden Fixup-DLLs. PSFLauncher injiziert die PSF-Laufzeit plus die benannten Fixups in den Prozess und startet dann die echte ausführbare Datei. Die Dateisystem-, Registry- und Bibliotheksladeaufrufe der Anwendung laufen durch die injizierten Fixups, bevor sie Windows erreichen.

PSFLauncher läuft zuerst, liest die Konfiguration, injiziert die Fixups und übergibt dann.

PSF behebt keine Fehler. Es übersetzt Annahmen.

Diese Unterscheidung ist wichtig, denn sie sagt Ihnen, wann Sie aufhören sollten, nach PSF zu greifen, und stattdessen das Paket reparieren sollten.

Die Symptomtabelle

Die Anwendung startet, findet aber sofort ihre eigenen Dateien nicht. Meist das Arbeitsverzeichnis. Die Anwendung ging davon aus, in ihrem Installationsordner zu starten, und startet nun woanders, sodass relative Pfade ins Leere laufen. Wenn kein Arbeitsverzeichnis deklariert ist, verwendet Windows System32, was fast nie das ist, was eine Legacy-Anwendung erwartet hat. Das ist die häufigste einzelne Ursache und die günstigste zu beheben, denn sie braucht einen workingDirectory-Wert in config.json und gar kein Umleitungs-Fixup. Prüfen Sie es vor allem anderen.

Die Anwendung startet, läuft und verliert Einstellungen zwischen Sitzungen. Dateiumleitung, über FileRedirectionFixup.dll. Die Anwendung schreibt die Konfiguration neben ihre ausführbare Datei, innerhalb des Pakets, wo Schreibvorgänge nicht bestehen bleiben. Der Schreibvorgang scheint zu gelingen und verläuft still im Nichts. Leiten Sie diese Pfade an einen benutzerspezifischen Ort um, und die Einstellungen überleben.

Die Anwendung schreibt in ihren eigenen Installationsordner und scheitert dann beim nächsten Start. Dieselbe Grundursache wie oben, nur heftiger sichtbar, weil die geschriebene Datei eine ist, die sie braucht. Dieselbe Lösung. Im Process Monitor liest sich das als Zugriff-verweigert-Ergebnis unterhalb des Paketordners.

Etwas schlägt nur bei Standardbenutzern fehl und funktioniert bei Administratoren. Meist Registry-Zugriffsrechte, behandelt von RegLegacyFixups.dll. Die Anwendung öffnet einen maschinenweiten Schlüssel und fordert mehr Zugriff an, als sie braucht, typischerweise Vollzugriff, obwohl sie nur liest. Ein Administrator kommt damit durch, ein Standardbenutzer nicht. Das Fixup schreibt den angeforderten Zugriff in etwas um, das der Container gewährt, über Umwandlungen wie Full2RW und RW2R. Es kann außerdem das Löschen von Schlüsseln vortäuschen, auf deren Entfernung die Anwendung besteht, und Schlüssel verbergen, die im Container nicht sichtbar sein sollten.

Ein Plug-in, Add-in oder Hilfsprogramm lädt nicht. Dynamisches Laden von Bibliotheken, über DynamicLibraryFixup.dll. Die Anwendung lädt etwas aus einem Pfad, den der Container anders auflöst, oder sucht eine Abhängigkeit, die sie maschinenweit installiert erwartet. Ihre Konfiguration setzt forcePackageDllUse und listet jede Bibliothek per name neben dem paketrelativen filepath auf, aus dem sie stammen soll. Das ist das Fixup, das am häufigsten eine nicht paketierte Abhängigkeit aufdeckt, was ein größeres Problem ist als ein Pfad.

Nichts Offensichtliches, und kein klares Muster. Erst tracen, mit TraceFixup.dll. Raten Sie nicht. Das Tracing-Fixup zeichnet auf, was die Anwendung tatsächlich anfragt, was aus einem Ratespiel eine kurze Liste macht. Jede Stunde im Tracing spart mehrere Stunden, in denen man Fixups auf Verdacht anwendet und sich fragt, welches geholfen hat.

Wie die Konfiguration tatsächlich aussieht

Alles davon lebt in einer Datei im Wurzelverzeichnis des Pakets, und die Form ist dieselbe, welches Fixup Sie auch anwenden:

{
  "applications": [
    { "id": "ContosoApp", "executable": "ContosoApp/ContosoApp.exe", "workingDirectory": "ContosoApp/" }
  ],
  "processes": [
    { "executable": "ContosoApp",
      "fixups": [
        { "dll": "FileRedirectionFixup.dll",
          "config": { "redirectedPaths": { "packageRelative": [ { "base": "ContosoApp/", "patterns": [ ".*\\.ini", ".*\\.log" ] } ] } } }
      ] }
  ]
}

Drei Dinge lohnt es sich zu verinnerlichen. Die id muss mit dem Id-Attribut des Application-Elements im Manifest übereinstimmen, sonst passiert nichts und Sie bekommen keine brauchbare Fehlermeldung. Die executable unter processes ist normalerweise der Dateiname ohne Pfad und Erweiterung, und sie wird als Muster behandelt, sodass ein unachtsamer Wert mehr Prozesse erfasst, als Sie gemeint haben. Und applications, processes und fixups sind allesamt Arrays, und so kommt ein Paket am Ende zu einem Stapel Fixups, den später niemand erklären kann.

Tracen, bevor Sie raten

Zwei Werkzeuge erledigen fast die gesamte Diagnosearbeit, und sie beantworten unterschiedliche Fragen.

Process Monitor sagt Ihnen, was an der Grenze zum Betriebssystem passiert ist. Filtern Sie auf Ihre ausführbare Datei, blenden Sie erfolgreiche Ergebnisse aus und lesen Sie die Liste von unten nach oben, weil dort die jüngsten Ereignisse stehen. Sie suchen nach zwei Formulierungen: Zugriff verweigert, und Pfad oder Name nicht gefunden. Die erste deutet meist auf Umleitung oder Registry-Zugriffsrechte hin. Die zweite deutet auf das Arbeitsverzeichnis hin.

Das Tracing-Fixup erzählt dieselbe Geschichte aus dem Prozess heraus, und es ist gezielt darauf ausgelegt, Kompatibilitätsfehler sichtbar zu machen. Fügen Sie die DLL dem Paket hinzu und ein Fragment in config.json:

{ "dll": "TraceFixup.dll", "config": { "traceLevels": { "filesystem": "allFailures" } } }

Standardmäßig filtert das Tracing Fehler heraus, die es für erwartbar hält, was meist gewünscht ist, denn Anwendungen versuchen routinemäßig, Dateien zu löschen, die es nie gab, und ignorieren das Ergebnis. Der Preis ist, dass sich ein echter Fehler in dem entfernten Rauschen verstecken kann. Beginnen Sie mit der Voreinstellung und erweitern Sie erst dann auf allFailures für den Bereich, den Sie verdächtigen, wenn die Standardansicht das Verhalten nicht erklärt hat.

Die Ausgabe geht an einen angehängten Debugger. Wenn Sie nicht debuggen, führen Sie DebugView von Sysinternals aus und lesen Sie sie dort. Das ist der gesamte Ablauf, und er ist weit schneller, als ein Fixup anzuwenden und zu hoffen.

Die Regel, die am meisten Zeit spart

Arbeiten Sie in dieser Reihenfolge:

  1. Reproduzieren Sie den Fehler mit einem Standardbenutzerkonto, nicht mit einem Administratorkonto. Die Hälfte aller Meldungen der Art „MSIX hat es kaputt gemacht" sind Berechtigungsannahmen, die schon immer da waren und vorher verdeckt wurden.
  2. Tracen Sie, bevor Sie reparieren. Finden Sie heraus, was die Anwendung anfragt.
  3. Reparieren Sie das Arbeitsverzeichnis, bevor Sie zu irgendeiner Umleitung greifen.
  4. Wenden Sie ein Fixup nach dem anderen an und testen Sie erneut. Drei auf einmal zu stapeln heißt, dass Sie nie erfahren, welches nötig war, und dass Sie alle drei für immer mitschleppen.

Dieser letzte Punkt wiegt schwerer, als er klingt. Fixup-Konfiguration ist etwas, das die nächste Person erbt. Ein Paket, das drei Fixups trägt, wo eines nötig war, ist ein Paket, das in zwei Jahren niemand anzufassen wagt.

Es gibt eine fünfte Regel, die sich nach ein paar Dutzend Paketen zeigt: Schreiben Sie das Warum auf, neben dem Paket, in einer Form, die die entscheidende Person überdauert. Eine Zeile pro Fixup, die das geheilte Symptom benennt, reicht. Ohne sie muss die nächste prüfende Person den ursprünglichen Fehler reproduzieren, bevor sie gefahrlos etwas entfernen kann, und deshalb werden so wenige Fixups je entfernt.

Wann PSF die falsche Antwort ist

PSF ist ein Kompatibilitäts-Shim, und Shims häufen sich an. Greifen Sie zu etwas anderem, wenn:

  • Die Anwendung einen Treiber oder einen Dienst auf Systemebene braucht. Das ist kein Container-Problem und kein Fixup wird es lösen. Wahrscheinlich sollte sie kein MSIX sein.
  • Die Anwendung wirklich maschinenweit schreiben muss und andere Anwendungen es lesen müssen. Umleitung macht diesen Schreibvorgang für alle anderen unsichtbar, was wie eine Lösung aussieht und keine ist.
  • Die Anwendung nur scheitert, wenn eine zweite Anwendung läuft. Kommunikation über gemeinsame Dateien, gemeinsame Registry-Schlüssel oder benannte Objekte übersteht die Containerisierung nicht sauber, und kein einzelnes Fixup adressiert das.
  • Sie beim vierten Fixup angekommen sind. An diesem Punkt lautet die ehrliche Antwort, dass diese Anwendung heute kein guter MSIX-Kandidat ist. MSI oder ein PowerShell App Deployment Toolkit Paket liefert sie mit weniger Aufwand aus, und Sie können später erneut hinschauen.

Zu wissen, wann man aufhört, ist der Unterschied zwischen einer Packaging-Praxis und einem wachsenden Haufen undokumentierter Shims. Es wirkt sich auch auf die Auslieferung aus: Ein Paket mit Fixups verhält sich unter App Attach anders als ein sauberes, was das Thema von was PSF für App Attach bedeutet ist.

Das wiederholt tun

Eine Anwendung auf diese Weise zu diagnostizieren, ist befriedigend. Es für vierhundert zu tun, ist ein Personalproblem, weshalb die Zuordnung meist im Kopf einer einzelnen Person lebt und mit ihr geht.

Im Maßstab einer ganzen Umgebung ist die Zuordnung außerdem die falsche Arbeitseinheit. Was Sie brauchen, ist ein Urteil pro Anwendung: geht so wie sie ist, geht mit Fixups, oder kann noch nicht umziehen. Schnell dorthin zu kommen, macht aus einer Legacy-zu-MSIX-Konvertierung statt eines offenen Projekts einen Zeitplan, und es ist der Rahmen hinter unserer Route Legacy-Anwendungen.

Wo EtherApps Forge ansetzt

EtherApps Forge richtet PSF-Fixups als Teil der Paketierung ein statt als separates Nacharbeitsprojekt danach, sodass die Entscheidung mit dem Paket festgehalten und nicht erinnert wird. Der breitere Ansatz steht auf unserer Route MSIX Packaging und Deployment, und die Fixup-Einrichtung selbst kam mit EtherApps Forge 1.0.6.

Die praktische Wirkung liegt in der Verteilung der Urteile und nicht bei einem einzelnen Paket. Anwendungen, die früher geparkt worden wären, weil sie sich im Container fehlerhaft verhielten, wandern stattdessen in die Kategorie „geht mit Fixups", mit angehängter Begründung, sodass die nächste Person, die das Paket öffnet, sehen kann, was entschieden wurde und warum.

EtherApps Forge ist eine Windows-Desktop-Anwendung mit einer kostenlosen 7-Tage-Testversion, sodass Sie die Diagnoseschleife an einer Anwendung erproben können, von der Sie bereits wissen, dass sie sperrig ist.

MSIX Packaging und Deployment entdecken

Beginnen Sie mit dem Arbeitsverzeichnis, tracen Sie, bevor Sie raten, und fügen Sie ein Fixup nach dem anderen hinzu.