Einleitung
Nachdem wir im 1. Teil des Tutorials unseren ersten Installer erstellt hatten, werden wir in diesem Teil die installierten Dateien auch wieder entfernen. Zudem werden wir einige weitere Wizard-Seiten anschauen und dem Benutzer die Möglichkeit geben, bestimmte Teile der Installation auszuwählen.
Uninstall
Dem Benutzer die Möglichkeit zu geben, unsere Anwendung wieder zu entfernen gehört nicht nur zum guten Ton, sondern hat auch für uns Vorteile:
- Für ein Update können die alten Dateien zuerst sauber entfernt werden. Somit gibt es keine Seiteneffekte durch alte Dateien, die eventuell für die neue Version nicht mehr benötigt werden.
- Wenn der Benutzer ein Programm von uns, dass ihm nicht gefallen hat, nur mit viel Mühe wieder los wird, wird er kaum ein anderes Produkt von uns ausprobieren.
Um unseren Installer aus dem 1. Teil um einen Uninstaller zu ergänzen kopieren wir das Script für den „First Installer“ und ändern/erweitern ihn so dass er folgendermassen aussieht:
OutFile "secondinstaller.exe"
InstallDir $PROGRAMFILES\MySecondInstaller
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles
Section ""
SetOutPath $INSTDIR
File C:\Windows\system32\notepad.exe
WriteUninstaller $INSTDIR\uninstall.exe
SectionEnd
Section "Uninstall"
Delete $INSTDIR\uninstall.exe
Delete $INSTDIR\notepad.exe
RMDir $INSTDIR
SectionEnd
Ausser dass wir den Namen in „Second Installer“ geändert haben sind drei Ergänzungen hinzugekommen:
UninstPage
Diese beiden Einträge geben an, dass für das Entfernen der installierten Dateien zwei Dialogseiten angezeigt werden sollen. Als erste die Bestätigungsseite, ob man wirklich die installierten Dateien entfernen will und als zweite die Seite, welche den Fortschritt des Deinstallierens anzeigt.
WriteUninstaller
Der Befehl WriteUninstaller schreibt die Routine für das Entfernen der Installation mit dem angegebenen Namen in den angegebenen Ordner.
Section "Uninstall"
Diese Section wird für das Entfernen der Installation aufgerufen. Als erstes wird der mit WriteUninstaller erzeugte Uninstaller entfernt. Danach wird die installierte Datei (notepad.exe) und zum Schluss das Installationsverzeichnis gelöscht.
Der Unistaller kann gelöscht werden, während er ausgeführt wird, da er zur Ausführung in das Temp-Verzeichnis des Systems kopiert wird.
Noch eine Anmerkung zur Variablen $INSTDIR. Diese enthält während der Deinstallation den Pfad, in dem sich der Uninstaller befindet. Falls man diesen mit WriteUninstaller z.B. in einen Unterordner „uninstall“ schreibt muss man dies während des Deinstallierens berücksichtigen, indem man die Pfade anpasst (z.B. $INSTDIR\..\notepad.exe).
Follow me
Vor der Installation möchte man dem Benutzer vielleicht noch mehr Informationen geben (Lizenzbedingungen) oder Angaben (Benutzer- und Firmenname) von ihm verlangen.
Um die Lizenzbedingungen anzuzeigen gibt es das Page license
Kommando. Mit dem Attribut LicenseData
wird die Datei angegeben, welche die Lizenzbedingungen enthält (im .txt oder .rtf Format). Das Attribut LicenseText
erlaubt es, den Text der oberhalb des Lizenztextes angezeigt wird anzupassen.
Die Abfrage von Benutzername und Passwort benötigt etwas mehr Aufwand. Als erstes muss man den Dialog definieren, d.h. wo soll welches Element angezeigt werden. Dies kann mit HM NIS Edit komfortabel über einen grafischen Editor erfolgen. Als Resultat ergibt sich eine Datei mit folgendem Inhalt:
NumFields=5
[Field 1]
Type=Label
Text=Name
Left=16
Right=34
Top=32
Bottom=40
[Field 2]
Type=Text
Left=64
Right=188
Top=30
Bottom=42
[Field 3]
Type=Label
Text=Company
Left=16
Right=45
Top=48
Bottom=56
[Field 4]
Type=Text
Left=64
Right=188
Top=46
Bottom=59
[Field 5]
Type=Label
Text=Please enter your Name and your Company
Left=16
Right=196
Top=4
Bottom=21
Am einfachsten ist es, diesen Text zu kopieren und in eine neue Datei mit dem Namen namecompany.ini einzufügen. Die Datei sollte im selben Ordner liegen wie das Installer-Script.
Im Installer-Script gibt es einiges anzupassen, so dass es wie folgt aussieht:
OutFile "thirdinstaller.exe"
InstallDir $PROGRAMFILES\MyThirdInstaller
Page license
Page custom getUsername
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles
LicenseData "license.txt"
Var UserName
Var Company
Function ".onInit"
InitPluginsDir
File /oname=$PLUGINSDIR\namecompany.ini "namecompany.ini"
FunctionEnd
Function getUsername
Push $R0
InstallOptions::dialog $PLUGINSDIR\namecompany.ini
Pop $R0
ReadINIStr $UserName "$PLUGINSDIR\namecompany.ini" "Field 2" "state"
ReadINIStr $Company "$PLUGINSDIR\namecompany.ini" "Field 4" "state"
MessageBox MB_OK "$UserName$\r$\n$Company"
Pop $R0
FunctionEnd
Section ""
SetOutPath $INSTDIR
File C:\Windows\system32\notepad.exe
WriteUninstaller $INSTDIR\uninstall.exe
SectionEnd
Section "Uninstall"
Delete $INSTDIR\uninstall.exe
Delete $INSTDIR\notepad.exe
RMDir $INSTDIR
SectionEnd
Die Erklärungen der Neuerungen:
Page custom
Mit diesem Kommando wird eine Benutzerdefinierte Seite hinzugefügt. Der Parameter getUsername
gibt dabei den Namen der Funktion an, die zur Anzeige der Seite aufgerufen werden soll. Die Funktion wird weiter unten erklärt.
Var
Um Variabeln benutzen zu können müssen diese zuerst deklariert werden. Da wir den Benutzernamen und den Firmennamen abfragen werden stellen wir hier zwei Variabeln zur Verfügung, um die eingegebenen Werte abzulegen.
Function ".onInit"
Dies ist eine sogenannte Callback-Funktion. Callback-Funktionen werden an bestimmten Punkten während des Ablaufs des Installers aufgerufen. .onInit
wird dabei aufgerufen, wenn der Installer die Initialisierung fast abgeschlossen hat.
Wir benutzen diese Callback-Funktion, um unsere Datei mit der Dialogdefinition in einen temporären Ordner zu entpacken. Dazu wird zuerst mit dem Befehl InitPluginsDir
das Verzeichnis $PLUGINSDIR
initialisiert. $PLUGINSDIR ist ein temporäres Verzeichnis, dass beim Beenden des Installers wieder gelöscht wird. Als nächstes wird unsere Datei in diesen Ordner kopiert. Somit steht sie während der Installation zur Verfügung.
Function getUsername
Hier nun die schon erwähnte Funktion. Das zentrale Element ist der Aufruf der Funktion „dialog“ aus dem Plug-In InstallOptions. Als Parameter wird die während der Initialisation entpackte Datei angegeben. Da die Funktion „dialog“ einen Rückgabewert auf den Stack speichert müssen wir diesen wieder vom Stack holen. Dazu speichern wir vor dem Aufruf der Funktion „dialog“ den in der Variablen $R0 vorhandenen Wert auf dem Stack. Nach dem ausführen der Funktion „dialog“ holen wir den Rückgabewert vom Stack. Wenn nötig kann der Rückgabewert nun ausgewertet werden. Bevor wir unsere Funktion verlassen stellen wir wieder den vorher auf dem Stack abgespeicherten Wert in die Variable $R0.
Mit ReadINIStr
lesen wir die eingegebenen Werte aus den Feldern in die entsprechenden Variablen ein. Diese zeigen wir in unserem Beispiel einfach mit einer MessageBox an, man könnte sie aber auch während der Installation in die Registry schreiben (mit WriteRegStr
). Die in die Registry geschriebenen Werte sollten dann aber bei der Deinstallation auch wieder gelöscht werden (mit DeleteRegKey
oder DeleteRegValue
).
Mehr Auswahl bitte …
Drei Dinge fehlen unserem Installer noch:
- Auswahl der zu installierenden Komponenten
- Startmenü-Eintrag
- Eintrag in der Systemsteuerung zum Entfernen der Software
Mit unserem vierten Installer erfüllen wir auch diese Wünsche. Wie gehabt folgen nach dem Script die Erklärungen der Änderungen.
!define INSTALLATIONNAME "MyForthInstaller"
OutFile "fourthinstaller.exe"
InstallDir $PROGRAMFILES\${INSTALLATIONNAME}
Page custom getUsername
Page license
Page components
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles
LicenseData "license.txt"
Var UserName
Var Company
Function ".onInit"
InitPluginsDir
File /oname=$PLUGINSDIR\namecompany.ini "namecompany.ini"
FunctionEnd
Function getUsername
Push $R0
InstallOptions::dialog $PLUGINSDIR\namecompany.ini
Pop $R0
ReadINIStr $UserName "$PLUGINSDIR\namecompany.ini" "Field 2" "state"
ReadINIStr $Company "$PLUGINSDIR\namecompany.ini" "Field 4" "state"
MessageBox MB_OK "$UserName$\r$\n$Company"
Pop $R0
FunctionEnd
Section ""
SetOutPath $INSTDIR
File C:\Windows\system32\notepad.exe
WriteUninstaller $INSTDIR\uninstall.exe
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${INSTALLATIONNAME}" "DisplayName" "Forth Installer"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${INSTALLATIONNAME}" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${INSTALLATIONNAME}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${INSTALLATIONNAME}" "NoRepair" 1
SectionEnd
Section "Sample Text File"
File "license.txt"
SectionEnd
Section /o "Another Sample Text File"
File "license2.txt"
SectionEnd
Section "Start Menu Shortcuts"
CreateDirectory "$SMPROGRAMS\${INSTALLATIONNAME}"
CreateShortCut "$SMPROGRAMS\${INSTALLATIONNAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
CreateShortCut "$SMPROGRAMS\${INSTALLATIONNAME}\notepad.lnk" "$INSTDIR\notepad.exe" "" "$INSTDIR\notepad.exe" 0
SectionEnd
Section "Uninstall"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${INSTALLATIONNAME}"
Delete $INSTDIR\uninstall.exe
Delete $INSTDIR\notepad.exe
Delete $INSTDIR\license.txt
Delete $INSTDIR\license2.txt
RMDir $INSTDIR
Delete "$SMPROGRAMS\${INSTALLATIONNAME}\*.*"
RMDir "$SMPROGRAMS\${INSTALLATIONNAME}"
SectionEnd
!define
Mit !define definieren wir eine Konstante, die den Namen unserer Installation enthält. Diese Konstante setzten wir dann jedes mal anstelle des Namens ein. Dadurch können wir den Namen einfach an einem Ort ändern und es geht kein Pfad etc. vergessen.
Page component
Durch diesen Eintrag wird die Auswahl der Komponenten angezeigt. Jede Section ist dabei eine Komponente und kann einzeln an- und abgewählt werden. Die Section mit dem leeren Namen wird dabei aber nicht angezeigt, wird aber immer installiert.
Section "Sample Text File"
Eine Section, die einer Komponente entspricht, die an- und abgewählt werden kann. Normalerweise ist eine Komponente automatisch angewählt und wird dementsprechend auch installiert. Falls man optionale Komponenten hat, die im Normalfall nicht installiert werden soll, gibt man diese mit dem Schalter /o (für optional) an.
CreateDirectory
CreateDirectory erzeugt das angegebene Verzeichnis. Falls dabei die in der Hierarchie höher gelegenen Verzeichnisse noch nicht existieren werden diese ebenfalls erstellt.
CreateShortCut
Mit CreateShortcut wird eine Verknüpfung mit dem angegebenen Pfad und Dateiname erstellt.
WriteRegStr, WriteRegDWORD
Um Werte in die Registry zu schreiben benutzt man die Commands WriteRegStr, WriteRegDWORD und ihre verwandten Commands. Falls der Key noch nicht vorhanden ist wird er automatisch erstellt.
DeleteRegKey
DeleteRegKey löscht dementsprechend einen Key aus der Registry.
Ausblick
Nachdem wir nun die Hauptelemente eines Installers behandelt haben betrachten wir im dritten Teil dieses Tutorials das Modern User Interface, um den Installern ein moderneres Erscheinungsbild zu geben.
Wie kann ich Verknüpfungen erstellen, die für alle Benutzer sichtbar sind?
aktuell verwende ich dies:
; Verknüpfungen
CreateShortCut „${ProfilePathAllUsers}\DESKTOP\${Installationname}.lnk“ „$INSTDIR\Auswertetool.exe“ „“
CreateDirectory „$SMPROGRAMS\${INSTALLATIONNAME}“
CreateShortCut „$SMPROGRAMS\${INSTALLATIONNAME}\Uninstall.lnk“ „$INSTDIR\Uninstall.exe“ „“ „$INSTDIR\Uninstall.exe“ 0
CreateShortCut „$SMPROGRAMS\${INSTALLATIONNAME}\${Installationname}.lnk“ „$INSTDIR\HelloWorld.exe“ „“ „$INSTDIR\HelloWorld.exe“ 0
CreateShortCut „$SMPROGRAMS\${INSTALLATIONNAME}\Dokumentation .lnk“ „$INSTDIR\Dokumentation\Dokumentation.pdf“ „“ „$INSTDIR\Dokumentation\Dokumentation.pdf“ 0
Wenn ich aber einen Adminuser beim installieren angebe, sind für meinen Benutzer keine Verknüpfungen sichtbar.. 🙁
Hallo brocel1
Bei NSIS ist der Machanismus folgendermassen vorgesehen:
CreateShortcut "$desktop\myapp.lnk" "$instdir\myapp.exe"
Dokumentation zu SetShellVarContext.
Pingback: NSIS Tutorial in c’t 16/2014 | of bits and bytes
Ein tolles Tutorial für den Einstieg-Danke. 🙂
Der thirdinstaller macht in Zeile 13 und 25 allerdings noch Probleme. Und behoben krieg ich sie mit meinem bisherigen Wissen leider nicht. 🙁
Ah…Fehler gefunden. Ich hätte vielleicht auch eine Datei license.txt mitliefern sollen.
Hallo White_Fox
Schön, dass dir das Tutorial gefällt. Und toll, dass Du den Fehler selber gefunden hast.
Ich denke, Du hast so schon eine gute Basis um Deinen eigenen Installer erstellen zu können.