Das WiX Toolset ist ein mächtiges Werkzeug um Installationsroutinen mit Hilfe von XML zu erzeugen.
Herzstück eines WiX Projektes ist das Product Element. Innerhalb diesem werden die Elemente der Installationsroutine definiert. Um außerhalb des Product Elements Installationselemente wie Components oder Directorys zu definieren wird ein Fragment Element benötigt, in welchem die einzelnen Elemente angelegt werden. Für die Übersichtlichkeit ist es daher sinnvoll eine neue Fragmentdatei außerhalb des Product Elements zu erzeugen.
Wer seine WiX Fragmente von Hand erzeugt, wird schnell merken, dass diese mit jeder Erweiterung der Software erneut angepasst werden müssen. Vor allem bei stetig wachsender Software kann dies zu Problemen führen. Nicht zuletzt, weil Fragmente gerne mal zu hunderten XML-Zeilen heranwachsen.
Schnell wird die Integration einer neuen DLL vergessen und die Anwendung startet nach Installation nicht.
An dieser Stelle ist die Frage angebracht ob man das Problem nicht automatisiert lösen kann?
Die Antwort ist: ja, man kann!
Das Harvest Tool „Heat“, welches im WiX Toolset mitgeliefert wird, bietet diverse Möglichkeiten um ganze Ordner, Projekte und sogar IIS Webseiten quasi zu „farmen“.
In diesem Blogpost wird speziell auf die Möglichkeit eingegangen, Verzeichnisse zu farmen.
Als Software kommen im Folgenden das WiX Toolset v3.10 sowie Visual Studio 2015 zum Einsatz.
Um aus einem Verzeichnis mit Heat ein Fragment zu erzeugen genügt der Aufruf von Heat über das MSBuild Target BeforeBuild innerhalb der .wixproj Datei. Der folgende Screenshot zeigt eine beispielhafte Definition eines solchen Aufrufs.
Wichtig ist der Aufruf der heat.exe über die MSBuild Task Exec. Heat benötigt zum Aufruf weitere Parameter. Die Wichtigsten werden im Folgenden vorgestellt:
- dir definiert das Ausgangsverzeichnis in welchem Heat beginnen soll. Es werden zusätzlich alle Unterordner durchforstet.
- -var gibt die Pfadvariable zur Datei an, in unserem Beispiel würden im Fragment alle Dateien im Source Attribut also den Wert „$(var.Persistence.WindowsService.TargetDir)\<Datei>“
Um die Projekt Referenz Variable TargetDir nutzen zu können, muss darauf geachtet werden, das zu installierende Projekt zu den Referenzen des WiX Installationsprojekts hinzuzufügen. - -dr gibt die Referenz zum gewünschten Directory innerhalb des Products. In dieses Verzeichnis werden die Komponenten während der Installation kopiert.
- -cg definiert den ComponentGroup Namen, welcher innerhalb der Feature Auflistung verwendet werden kann.
- -ag lässt GUIDs zur Kompilierungszeit automatisch über „*“ generieren. Dies ist für Components problemlos möglich, da die GUID über den Pfad erzeugt wird und so jedes Mal gleichbleibt.
- -o definiert den Output Pfad in welchen das Fragment erzeugt werden soll.
Heat besitzt noch weitere Parameter, diese können bei Bedarf in der Dokumentation nachgelesen werden.
Das von Heat erzeugte Fragment hat die Form, welche im folgenden Screenshot dargestellt ist.
Zunächst wird ein Fragment geöffnet und das über -dr angegebene Verzeichnis über DirectoryRef referenziert. Anschließend werden alle Komponenten sowie Dateien gelistet. Abschließend wird ein zweites Fragment geöffnet und die ComponentGroup wird mit den einzelnen Komponentenreferenzen zusammengefügt.
Die so erstellte ComponentGroup kann nun innerhalb des Produktfeatures einfach über eine Id eingebunden werden.
Ab diesen Zeitpunkt müssen Sie sich nun keine Sorgen mehr darüber machen, dass z.B. Assemblies aus neuen NuGet Paketen nicht mehr eingebunden werden. Dank des zuvor angepassten BeforeBuild MSBuild Targets wird bei jedem Build das Fragment neu erzeugt.
Filterung
Mit jedem Build überschreibt Heat den Inhalt der erzeugten Datei. Dieses Verhalten kann vor allem störend sein, wenn bestimmte Dateien während der Installation ignoriert werden sollen.
Was also tun, wenn bestimmte Dateien gesondert behandelt werden sollen? Auch hier bietet Heat eine Lösung: Filter in Form von XSLT Dateien.
Soll also exemplarisch die Datei „DoNotCopyThisFile.config“ nicht mitgeliefert und im Fragment ignoriert werden, muss eine neue XSLT Filter Datei angelegt werden.
Den beispielhaften Code zeigt der folgende Screenshot.
Die Filterdatei muss nun über den Parameter -t zum Heat Aufruf im MSBuild Target BeforeBuild hinzugefügt werden. Beispiel:
„WIX)bin\heat.exe“ dir $(SolutionDir)Persistence.WindowsService\bin\$(Configuration) -var var.Persistence.WindowsService.TargetDir -t Filter.xslt -dr INSTALLLOCATION -cg PersistenceServiceBinariesCG -ag -scom -sreg -sfrag -srd -o $(ProjectDir)Fragments\BinariesFragment.wxs
Aufgrund des Filters werden nun alle File Elemente nach dem Source Attribut geforstet und auf den angegebenen Wert überprüft. Wurde eine Übereinstimmung gefunden wird die Id der Datei gespeichert und anschließend jede Component sowie ComponentRef, welche die Id beinhaltet, entfernt.
Sollte die Component um diverse Funktionen erweitert werden müssen, kann Sie nun manuell in einem neuen Fragment bzw. einer neuen ComponentGroup bearbeitet werden.
Fazit
Um die Inhalte Ihrer Installationsroutinen automatisiert auf dem aktuellsten Stand zu halten, müssen sie ihre WiX Fragmente nicht immer händisch bearbeiten. Mit nur wenigen Anpassungen ist es möglich mit Hilfe von Heat Fragmente automatisch erzeugen zu lassen. Gibt es Sonderfälle, so können auch diese mit Hilfe von Filtern praktisch angegangen werden.
Im Rahmen unserer Blogserie über das WiX Toolkit erfahren Sie außerdem wie Sie unkompliziert Installer mit Hilfe des WiX Toolsets erstellen können.
Cooler Artikel! Ich persönlich finde den Umgang mit Heat nicht immer intuitiv; den Nutzen kann man aber kaum in Frage stellen – insbesondere bei automatischen Builds.
Achja, hier noch eine nette Anekdote: Ich habe Rob Mensching (Entwickler von WiX) mal darauf angesprochen, ob ihm bewusst wäre, dass die Aussprache von WiX im Deutschen bei uns zu Belustigungen führt (man denke nur an die berühmten Visual Studio WiX-Vorlagen…). Seine Antwort darauf: “Yeah, we knew about the name before we released it back in 2004. There was a slight chuckle back then knowing that it would be “WiX on SourceForge”.”
🙂
Gruß,
Christian.
P.S.: Wir nutzen WiX auch zur Erstellung von Setups von VSTO Add-Ins inklusive digitale Signierung. Macht ihr das auch?