Alles WiX oder was – Windows Installer XML toolset für Dummies

Im Zuge der Zukunftssicherung (Heute nennt man das Refactoring) eines meiner älteren aber immer noch aktiven Projekte, einem Windows Forms Projekt sollte es dieses mal nicht nur dem eigentlichen Code sondern dem gesamten Build und Deployment Prozess an den Kragen gehen.

imageMit den, bis zur Visual Studio 2010 enthaltenen, und Stand Heute mit der nächsten Visual Studio Version nicht mehr unterstützen, “Visual Studio Setup Projekte”, war ich eigentlich noch nie wirklich zufrieden. Also muss etwas neues her, mit dem ich dieses ungeliebte Setup Projekt ersetzen kann und mein Projekt auch noch mit der nächsten Visual Studio Version weiter entwickeln und distribuieren kann.

Nach ein wenig Recherche und ein wenig Gezwitscher auf Twitter stand fest, dass WiX wohl die beste Lösung sei um das Deployment der Anwendung durchzuführen.

WiX ist ein von Microsoft initiiertes Open Source Projekt dass unter anderem von Microsoft selbst für die  Distribution von Microsoft Office verwendet wird.

Nachdem klar war, das WiX in Zukunft bei mir für die Installation meines Projektes zuständig sein soll, habe ich über Twitter von Sebastian Seidel einen Link auf einen Beitrag erhalten in welchem beschrieben wird wie man in 5 einfachen Schritten aus einem Visual Studio Setup ein WiX Setup Projekt machen kann.

Ich bin dann dieser Anleitung gefolgt und habe die Konvertierung und Änderungen laut dem oben genannten Beitrag durchgeführt.

Wobei ich sagen muss, dass diese Konvertierung zwar ganz schön ist, aber leider nicht so ohne weiteres direkt zum Erfolg führt.

imageIch habe dann mit ein wenig Hilfe von Sebastian, Danke noch mal dafür, relativ schnell, erst einmal ein generell funktionierendes Setup mit WiX zum laufen bekommen. Leider noch ohne wirklich zu wissen wie WiX tatsächlich funktioniert und wie umfangreich WiX in Wirklichkeit ist.

Da ich aber nicht so leicht zufrieden zu stellen bin und mir das WiX Setup,  welches aus dem decompilierten alten Setup erstellt wurde, nicht gefallen hat (da waren zu viele statische Angaben enthalten und es hatte keine echte nachvollziehbare Struktur) habe ich mich mit WiX näher beschäftigt.

Nachdem ich ein paar Tage mit WiX gearbeitet habe, würde ich sagen, dass es sich nicht lohnt ein Setup Projekt zu decompilieren um dieses dann manuell nachzuarbeiten.

Meiner Meinung nach ist es einfacher ein Basistemplate mit den wichtigsten Funktionalitäten, gepaart mit ein wenig Grundwissen über WiX zu nehmen und sich das benötigte Setup Projekt manuell zu erstellen.

Und genau ein solches Basistemplate möchte ich hier zusammen mit dem notwendigen Basiswissen zu WiX vorstellen und vermitteln.

Wer WiX noch nicht auf seinem Rechner installiert hat, sollte das nun aber spätestens nachholen.

Hier der Link zum Download von WiX

Nachdem man WiX installiert hat und Visual Studio startet, findet man dort neue Projektvorlagen:

SNAGHTMLb687d8

In diesem Beitrag dreht sich alles nur um das eigentliche Setup Projekt die anderen Projekt Vorlagen sind dann eher für die Fortgeschrittenen.

Um die Funktionsweise von WiX direkt selbst ausprobieren zu können, habe ich ein Testprojekt erstellt dass sowohl eine Windows Forms Anwendung, wie eine Class Library und das zugehörige Wix Setup Projekt in einer Solution enthält.

Also einfach die Solution (VS2010) herunterladen, entpacken, BS starten und loslegen.

Der Einfachheit halber habe ich alle Erklärungen direkt als Kommentar in das WiX Skript aufgenommen.

So hier das WiX Script zum anschauen. Im Anschluss folgt dann auch noch der Link zum herunterladen der gesamten Test Solution.

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <!--  <?define Manufactor = "Hans-Peter Schelian"?>
        Anstelle den Manufactor an mehreren Stellen anzugeben weise ich hier lieber einer Variablen den Wert zu
        und verwende im weiteren Verlauf einfach die Variable
  -->
  <!--  <?define UpgradeGuid = "{3B563A68-99BC-4528-9356-295ADB67909A}"?>
        Ganz Wichtig, die Guid für den UpgradeCode darf nach der ersten Installation nicht mehr geändert werden
        aus diesem Grund weise ich diese Guid einer Variablen zu die ich dann im weiteren Verlauf im Bereich
        <Product UpgradeCode="$(var.UpgradeGuid)" /> und  im Bereich <Upgrade Id="$(var.UpgradeGuid)" anstelle
        der Eingabe der eigentlichen Guid verwenden kann.
  -->

  <!-- Hier nun alle Defines die durch den Präprozessor aufgelöst werden -->
  <?define Manufactor = "Hans-Peter Schelian"?>
  <?define UpgradeGuid = "{3B563A68-99BC-4528-9356-295ADB67909A}"?>

  <!--  Erklärungen zum Bereich <Product> Siehe auch http://wix.sourceforge.net/manual-wix3/wix_xsd_product.htm

        Id="*" Mit dem + wird erreicht, dass bei jedem erzeugen des Setup eine neue Guid erstellt wird.
          Man könnte natürlich auch alternativ eine feste Guid vergeben, dass würde dann so ausssehen:
          Id="{2BE1FDE8-FAEE-48B5-AA08-FD2FE26D7FB2}"

        Name="WiXDemoProjekt" Name des Projektes wie es in "Programme und Funktionen" angezeigt wird

        Version="!(bind.FileVersion.MyApplicationFile)" - Das ist die Programmversion des Produktes,
          entweder man muss die Version manuell angeben: Version="1.0.1.1" oder man kann wie ich es hier
          demonstriere, Binder Variablen des WiX Linker verwenden um Dynamisch die Vesionsnummer aus
          einer beliebiegen Datei des Projektes zu ermitteln.
          Im Beispiel verwende ich die Möglichkeit die Version welche mit [assembly: AssemblyFileVersion("1.0.0.0")]
          in der AssemblyInfo gesetzt wurde aus der Datei auszulesen.

        Manufacturer="$(var.Manufactor)" Zuweisung des in der Präprozessor Variablen gespeicherten Herstellers,
          alternativ kann man natürlich auch eine manuelle Zuweiung Manufacturer="Hans-Peter Schelian" vornehmen

        UpgradeCode="$(var.UpgradeGuid)"> Zuweisung der in der Präprozessor Variablen gespeicherten Guid,
          alternativ kann man die Zuweisung UpgradeCode="{2BE1FDE8-FAEE-48B5-AA08-FD2FE26D7FB2}"> auch manuell
          durchführen.
  -->
  <Product
  Id="*"
  Name="WiXDemoProjekt"
  Language="1033"
  Version="!(bind.FileVersion.MyApplicationFile)"
  Manufacturer="$(var.Manufactor)"
  UpgradeCode="$(var.UpgradeGuid)">

    <!-- Erklärungen zum Bereich <Package> http://wix.sourceforge.net/manual-wix3/wix_xsd_package.htm
      InstallerVersion="200" Ab Windows Installer 2.0
      Compressed="yes" - So werden die Dateien im MSI File komprimiert
      Description="Installiert das WiXDemoProjekt" - Eine Beschreibung für das Installer Package
      Manufacturer="Hans-Peter Schelian" - Und wieder der Hersteller siehe auch <Procuct Manufacturer="" />
      Comments="Ich wünsche allen viel Spaß mit diesem Beispiel" - Das was es bedeutet ein Kommentar
    -->
    <Package
    InstallerVersion="200"
    Compressed="yes"
    Description="Installiert das WiXDemoProjekt"
    Manufacturer="$(var.Manufactor)"
    Comments="Ich wünsche allen viel Spaß mit diesem Beispiel"
  />

    <!-- Erklärungen zum Bereich <Media> Siehe auch http://wix.sourceforge.net/manual-wix3/wix_xsd_media.htm
    -->
    <Media
    Id="1"
    Cabinet="media1.cab"
    EmbedCab="yes"
  />

    <!-- ARP Support Oder wie konfiguriert man Add/Remove Programs mit dem Windows Installer
        Siehe auch http://msdn.microsoft.com/en-us/library/aa368032.aspx
    -->
    <Property Id="ARPHELPTELEPHONE" Value="XXXXX/XXXXXXX" />
    <Property Id="ARPHELPLINK" Value="https://blog.schelian.de" />
    <Property Id="ARPCONTACT" Value="Schelian IT Beratung" />
    <Property Id="ARPCOMMENTS" Value="Alles WiX oder was" />
    <Property Id="ARPURLINFOABOUT" Value="http://www.schelian.de" />

    <!-- Erklärungen zum Bereich <Upgrade>
        Upgrade Id="$(var.UpgradeGuid)"> hier Zuweisung durch Präprozessor Variable, siehe auch Hinweise
          zu define UpgradeGuid

        <UpgradeVersion Minimum="!(bind.FileVersion.MyApplicationFile)" - Hier wird festgestellt ob
          bereits ein neueres Produkt (Neuere Version) installiert ist.

        <UpgradeVersion Minimum="0.1.0.0" - Prüfung ob bereits eine frühere Version installiert ist

        <UpgradeVersion Minimum="1.0.0.0" Maximum="99.0.0.0" - Ist das Prpdukt in welcher Versio auch immer
            bereits auf dem Rechner installiert, dann setzt die internet Variable PREVIOUSVERSIONSINSTALLED,
            dadurch wird verhindert, dass selbst dann wenn man eine Version die nicht als Upgrade gilt
            (nur im vierten Bereich) der Versionsnummer geändert ist, nicht dazu führt, dass es zu doppelten
            Einträgen im Add/Remove Programms kommt.
    -->
    <Upgrade Id="$(var.UpgradeGuid)">
      <UpgradeVersion Minimum="!(bind.FileVersion.MyApplicationFile)"
                      IncludeMinimum="no"
                      OnlyDetect="yes"
                      Language="1033"
                      Property="NEWPRODUCTFOUND" />
      <UpgradeVersion Minimum="0.1.0.0"
                      IncludeMinimum="yes"
                      Maximum="!(bind.FileVersion.MyApplicationFile)"
                      IncludeMaximum="no"
                      Language="1033"
                      Property="UPGRADEFOUND" />
      <UpgradeVersion Minimum="1.0.0.0" Maximum="99.0.0.0"
         Property="PREVIOUSVERSIONSINSTALLED"
         IncludeMinimum="yes" IncludeMaximum="no" />
    </Upgrade>

    <!-- So nun wird die Verzeichnis Struktur für die Installation aufgebaut
      <Directory Id="TARGETDIR" Name="SourceDir"> Diese Zeile setzt das Root Verzeichnis der Installation
        "\"
      <Directory Id="ProgramFilesFolder"> verwendet eine durch den Windows Installer vordefinierte Id zur
        Verwendung der Standard Programmpfads.
        "C:\Program Files"
      <Directory Id="CompanyFolder" Name="Schelian IT Beratung">
        "C:\Program Files\Schelian IT Beratung\"

      <Directory Id="INSTALLLOCATION" Name="WiXDemoProjekt">
        "C:\Program Files\Schelian IT Beratung\WiXDemoProjekt\"
    -->
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="CompanyFolder" Name="Schelian IT Beratung">
          <Directory Id="INSTALLLOCATION" Name="WiXDemoProjekt">
            <!-- Und dahinein packen wir eine Component, in diesem Fall Unser Ausführbares Programm
                Jede Component muss eine eindeutige Id bestzen, diese wird weiter unter verwendet um die Component
                einem Feature zuzuordnen.
                Eine Component sollte eine Guid besitzten, damit es später Möglich ist anhand dieser Guid die Datei
                eindeutig zu identifizieren, damit man mit dem MS Installer, eine Reparatur einer vorhandenen Installation
                durchführen kann.
            -->
            <Component Id="ProductComponent" Guid="{4A5619DF-5841-48EC-8D7C-D368718C6D1A}">
              <!-- Innerhalb der Komponente bestimmen wir dann die zu installierende Datei
                  Jedes File muss einen eindeutige Id besitzen, der Name ist der Dateiname am Zielort und
                  mit Source wird die Quelle der Datei angegeben.

                  Name="$(var.WixDemoProjekt.TargetFileName)" nutzt die Möglichkeit den Zielnamen aus dem
                  Visual Studio Projekt zu übernehmen, dass hat den Vorteil, dass man sich keine Gedanken
                  darüber machen muss das Setup anfassen zu müssen, wennm man den Ausgabe Namen im VS Projekt
                  ändert.

                  Source="$(var.WixDemoProjekt.TargetPath)" nutzt ebenfalls die Möglicheit der Visual Studio
                  Project References und Variablen.
                  Siehe auch http://wix.sourceforge.net/manual-wix3/votive_project_references.htm
                  Man miuss übrigens um diese References nutzen zu können im WiX Setup Projekt eine Reference auf das
                  Visual Studio Projekt setzen.

                  KeyPath="yes" Für nähere Informatinonen siehe http://wix.sourceforge.net/manual-wix3/wix_xsd_file.htm
              -->
              <File Id="MyApplicationFile" Name="$(var.WixDemoProjekt.TargetFileName)" Source="$(var.WixDemoProjekt.TargetPath)" KeyPath="yes">
                <!-- Dann legen wir doch gleich noch einen Desktop Shortcut für das Projekt an. -->
                <Shortcut Advertise="yes" Id="DesktopShortCut" Name="WiXDemoProjekt" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" Description="WiXDemoProjekt Programm ausführen" Icon="Icon.exe">
                  <!-- Und dieses Icon soll für den Shortcut verwendet werden -->
                  <Icon Id="Icon.exe" SourceFile="$(var.WixDemoProjekt.TargetPath)" />
                </Shortcut>
              </File>
            </Component>
            <!-- Nun muss für jedes weitere File dass installiert werden soll, eine Component erstellt werden
                Es wäre auch möglich mehrere Files in einer Component zusammenzufassen, allerdings würde ich das
                nur empfehlen, wenn man tgatsächlich einzeln zu installierende Feature implementiert, die je
                Component aus mehereren Dateien bestehen.
            -->
            <Component Id="WiXDemoLib" Guid="{777028E8-DA56-400E-9C71-844AE328E8BF}">
              <!-- Hier nun die zu installierende Datei der Component hinzufügen -->
              <File Id="WiXDemoLib" Name="WiXDemoLib.dll" Source="$(var.WixDemoProjekt.TargetDir)WiXDemoLib.dll" KeyPath="yes" />
            </Component>
            <!-- Beispiel wie man eine App.Config in das Setup aufnehmen und während der Setup Erstellung umbenennen kann
                Hier wird aus der app.config die WixDemoProjekt.Exe.Config
            -->
            <Component Id="app.config" Guid="{EE4CA09D-2C10-48E4-946A-D8B9242F557E}">
              <File Id="app.config" Name="WixDemoProjekt.Exe.Config" Source="$(var.WixDemoProjekt.ProjectDir)app.config" KeyPath="yes" />
            </Component>
            <!-- Und hier ein Beispiel wie man Datei in Unterverzeichnis am Zielort kopieren kann-->
            <Directory Id="IMAGEFOLDER" Name="Images">
              <Component Id="WiX.image" Guid="{ACD0322F-8170-4C67-84BC-161FCEE6274A}">
                <File Id="WiX.image" Name="wixlogo.png" Source="$(var.WixDemoProjekt.TargetDir)images\wixlogo.png" KeyPath="yes" />
              </Component>
            </Directory>
          </Directory>
        </Directory>
      </Directory>

      <!-- Verknüpfungen im Startmenü setzen
          Siehe auch http://wix.sourceforge.net/manual-wix3/create_start_menu_shortcut.htm
      -->
      <Directory Id="ProgramMenuFolder">
        <Directory Id="MyShortCutsDir" Name="WiXDemoProjekt">
          <Component Id="ShortCutComponent" Guid="{B51BC276-F509-4F25-9738-EE176445D073}">
            <Shortcut Id="ProgShortCut" Name="WiXDemoProjekt" Description="WiXDemoProjekt Programm Verkmüpfung" Target="[INSTALLLOCATION]WixDemoProjekt.Exe"></Shortcut>
            <Shortcut Id="UninstallShortCut" Name="Uninstall WiXDemoProjekt" Target="[System64Folder]msiexec.exe" Arguments="/x [ProductCode]"/>
            <RemoveFolder Id="RemoveMyShortCuts" On="uninstall"/>
            <RegistryValue Root="HKCU" Key="Software\Schelian IT Beratung\WiXDemoProjekt" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
          </Component>
        </Directory>
      </Directory>
      <!-- Wird benötigt um den Desktop Shortcut anlegen zu können -->
      <Directory Id="DesktopFolder" Name="Desktop" />
    </Directory>

    <!-- Feature Bereich hier als Basistemplate nur ein Feature (Alles installieren)
        Siehe auch http://wix.sourceforge.net/manual-wix3/wix_xsd_feature.htm
    -->
    <Feature Id="ProductFeature" Title="WiXDemoProjekt" Level="1">
      <ComponentRef Id="ProductComponent" />
      <ComponentRef Id="WiXDemoLib" />
      <ComponentRef Id="app.config" />
      <ComponentRef Id="WiX.image" />
      <ComponentRef Id="ShortCutComponent" />
    </Feature>

    <!-- Das was nun folgt ist schon ein wenig Finetuning CustomActions
        siehe auch http://wix.sourceforge.net/manual-wix3/wix_xsd_customaction.htm
    -->
    <!-- Keinen Downgrade zulassen -->
    <CustomAction Id="PreventDowngrading"
                  Error="Es ist bereits eine neuere Version instlliert." />

    <!-- Nun noch die auszuführende Reihenfolg angeben
        siehe auch http://wix.sourceforge.net/manual-wix3/wix_xsd_installexecutesequence.htm
    -->
    <InstallExecuteSequence>
      <Custom Action="PreventDowngrading"
              After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
      <RemoveExistingProducts After="InstallFinalize" />
    </InstallExecuteSequence>

    <!-- Wenn ein neueres Produkt gerunden wurde, soll das auch in der UI ausgegeben werden
        siehe auch http://wix.sourceforge.net/manual-wix3/wix_xsd_installuisequence.htm
    -->
    <InstallUISequence>
      <Custom Action="PreventDowngrading"
              After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
    </InstallUISequence>

    <!-- So kann man eine eigene Lizenzmeldung ausgeben -->
    <WixVariable Id='WixUILicenseRtf' Overridable='yes' Value='$(var.WixDemoProjekt.ProjectDir)Lizenzbestimmungen.rtf'/>

    <!-- UI Definition für Minimales Setup
    Um diese UI Definition vornehmen zu können,
    muss im WiX Projekt die WixUIExtension.dll als Reference hinzugefügt werden
    -->
    <UIRef Id="WixUI_Minimal" />
    <UIRef Id="WixUI_ErrorProgressText" />
  </Product>
</Wix>

WixDemoProjekt (VS2010 Solution)

4 Gedanken zu „Alles WiX oder was – Windows Installer XML toolset für Dummies“

    1. Hallo Ich möchte mich auch bedanken Für die Beschreibung.
      Ich habe eine frage kann mir jemand villeicht helfen.
      ich arbeite mit wix toolset und habe schon setup erstellt und in registry auch reingepackt aber ich will auch meine installation in Programdata sehen.das heißt dass der Program zu Benutzer zeigt welche program willst du ausführen normaleweise muss man mit Customaction oder event schreiben aber ich weiß es nicht wie ich das machen soll:(

      1. Wenn du in das Startmenü eines Benutzers schreiben möchtest, dann benötigst du keine CustomAction.

        Als erstes musst du deine Ordnerstruktur um den Ordner ProgramMenuFolder erweitern. Anschließend kannst du darin mit dem ShortCut Element eine Verknüpfung auf die gewünschte(n) Datei(en) erstellen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.