Tutorial: Script- und Modinstaller mit dem NSIS erstellen

Hier ist der ideale Ort um über Scripts und Mods für X³: Terran Conflict und X³: Albion Prelude zu diskutieren.

Moderators: Moderatoren für Deutsches X-Forum, Scripting / Modding Moderators

Post Reply
User avatar
Samuel Creshal
Posts: 17833
Joined: Sat, 6. Mar 04, 16:38
x3tc

Tutorial: Script- und Modinstaller mit dem NSIS erstellen

Post by Samuel Creshal » Mon, 29. Dec 08, 22:51

Tutorial: Script- und Modinstaller mit dem Nullsoft Scriptable Installer System (NSIS) erstellen

In diesesm Tutorial beschreibe ich, wie man (mehr oder weniger) einfach mit dem NSIS Installer für seine Scripte/Mods schreibt.
Der Weg über einen NSIS-Installer hat gegenüber dem Plugin Manager oder einer manuellen Verteilung in zip/rar/7z-Archiven den Vorteil, dass der Benutzer keinerlei Zusatzprogramme braucht. Da der NSIS die selbe Kompressionsmethode wie 7zip benutzt, sind die damit gepackten Archive zudem sehr kompakt.
Nachteil gegenüber dem Plugin Manager ist, dass hierbei nur komplette Dateien ersetzt werden können und keine Kollisionserkennung möglich ist. Hiermit erstellte Archive sind an das normale cat/dat-Archiv gebunden, mit den damit verbundenen Kompatibilitätsproblemen.
Ein Beispiel dafür, was mit dem NSIS möglich ist, ist mein HUD-Mod: http://forum.egosoft.com/viewtopic.php?t=221008 Der NSIS ermöglicht es hier, dass beliebige Kombinationen von cats/dats in korrekter Nummerierung als Fakepatch installiert werden, und über die Systemsteuerung deinstalliert werden können.

Vorbereitung: Notwendige Programme, Konventionen
Was ihr auf jeden Fall braucht, ist der NSIS selber: http://nsis.sourceforge.net/Download
Bei der Komponentenauswahl während der Installation achtet darauf, dass ihr das „Modern User Interface“, die „Language Files“ sowie „Language DLL“, „nsDialog“ und „nsExec“ mitinstalliert.
Zudem zwingend benötigt wird ein Texteditor. Notepad tuts zur Not auch, etwas komfortabler ist Notepad++ (http://notepad-plus.sourceforge.net/de/ ... hp?lang=de).
Optional ist ein Grafikbearbeitungsprogramm wie GIMP oder Paint.NET, falls ihr eurem Installer eigene Icons hinzufügen wollt.
Information zu meinem Schreibstil: Quelltexte in Code-Blöcken können 1:1 kopiert und ausprobiert werden. Platzhalter sind entweder mit <> gekennzeichnet (<schlauen Kommentar hier einfügen>), bei Beispielen benutze ich als Platzhalter „foo“, „bar“, „bla“ und ähnliches – das ist ebenfalls ersetzbar.

Einführung
Die Anweisungen, wie der Installer auszusehen hat, werden in .nsi-Dateien geschrieben und dann mit dem Programm „makensisw“ kompiliert. Die .nsi-Dateien sind einfache Textdateien und können daher mit einem beliebigen Texteditor bearbeitet werden.
NSI-Dateien bestehen aus mehreren Abschnitten: Die eigentlichen Informationen, welche Dateien wohin installiert werden, sind in sogenannten „Sections“:

Code: Select all

Section "<Name>" <ID>
	; Hier stehen die Anweisungen
SectionEnd
Kommentare werden mit ; eingeleitet, bei den Schlüsselwörtern wie „SectionEnd“ sollte auf die Groß-/Kleinschreibung geachtet werden.
Sektionen erscheinen auch als an- bzw. abwählbare Option im Installer. Der Name der Sektion wird bei dieser Auswahl angezeigt, im Installer intern wird die ID verwendet. Der Name muss daher nicht zwangsläufig vergeben werden.
Neben Sektionen gibt es noch Funktionen, die vom Installer nicht angezeigt werden, und manuell aufgerufen werden können:

Code: Select all

Section Foo
	Call Bar ; ruft die Funktion Bar auf
SectionEnd
Function Bar
	;Hier die Anweisungen
FunctionEnd
Globale Optionen festlegen
Diese Optionen sind unabhängig von den einzelnen Sektionen. Teilweise sind es Anweisungen für den makensisw-Compiler, wie er die Datei handzuhaben hat, teilweise sind es Einstellungen des Installers. Hier die wichtigsten:

Code: Select all

OutFile "<Name>.exe" ; Der Name der fertigen Installer-Datei
RequestExecutionLevel admin ; Für Vista relevant: Installation benötigt Adminrechte
SetCompressor /SOLID lzma ; Legt die Kompression fest. LZMA benötigt mehr Zeit beim Kompilieren, erzeugt aber die kleinsten Archive.
InstallDir "$PROGRAMFILES\<Ordner>\" ; Das Zielverzeichnis. Kann vom User noch geändert werden
InstallDirRegKey HKLM "Software\<Pfad>" "" ; Damit wird das Zielverzeichnis in der Registry gespeichert und kann bei der Deinstallation ausgelesen werden.
Caption "<Titel>" ; Titel des Installers
BrandingText "<Name, Firma, URL oÄ>" ; Legt den Copyright-Text links unten fest.
Name "<Name>" ;Name des Installers, wird bpsw. auf der Begrüßungseite angezeigt
!include <lib>.nsh ; Hiermit werden zusätzliche Komponenten eingebunden.
Dateien installieren und deinstallieren
Die Installation von Dateien ist recht einfach: Zuerst gebt ihr (in der Section) mit „SetOutPath“ an, wohin die Dateien installiert werden sollen, danach gebt ihr mit „File“ die Dateien an:

Code: Select all

OutFile test.exe
InstallDir "C:\foo"
Section Example
	SetOutPath $INSTDIR
	File readme.txt
	WriteUninstaller $INSTDIR\foo.exe
SectionEnd
Section Uninstall ; den Namen NICHT ändern!
	Delete $INSTDIR\readme.txt
	Delete $INSTDIR\foo.exe
SectionEnd
Bei diesem Beispiel wird die Datei „readme.txt“ (die bei der Kompilierung im selben Ordner liegen muss wie die .nsi-Datei) zusammen mit dem Uninstaller foo.exe in den Ordner $INSTDIR installiert, den wir weiter oben festgelegt haben. Bei der Deinstallation werden beide Dateien wieder gelöscht.

BlingBling!
Bisher sieht der Installer nicht wirklich berauschend aus, das ändert sich jetzt mit der Einführung des Modern User Interface, kurz MUI. Das MUI verbessert viele Aspekte des NSIS und ist zudem halbwegs einfach zu handhaben, daher gehe ich gleich dazu über.
Das MUI wird per

Code: Select all

!include MUI2.nsh
am Dateianfang eingebunden. Zudem können viele Optionen global festgelegt werden:

Code: Select all

!define MUI_ICON <name>.ico ; Legt das Symbol des Installers fest
!insertmacro MUI_PAGE_DIRECTORY ; Gibt dem user die Möglichkeit, das Zielverzeichnis zu ändern
!insertmacro MUI_PAGE_COMPONENTS ; Bietet die Möglichkeit, einzelne Sektionen an- bzw. abzuwählen
!insertmacro MUI_PAGE_INSTFILES ; ACHTUNG: Dieses Macro muss IMMER eingebunden werden, wenn Dateien installiert werden sollen!
!insertmacro MUI_LANGUAGE "<Sprache>" ; Damit können mehrere Sprachen eingebunden werden - dazu später mehr
Eine vollständige Auflistung findet sich unter http://nsis.sourceforge.net/Docs/Modern ... eadme.html, aber das hier sollte für den Anfang genügen.
Ein einfacher einsprachiger Installer mit dem MUI:

Code: Select all

!include MUI2.nsh
OutFile test.exe
InstallDir "C:\foo"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
Section Example
	SetOutPath $INSTDIR
	File test.bmp
	WriteUninstaller $INSTDIR\foo.exe
SectionEnd
Section Uninstall ; den Namen NICHT ändern!
	Delete $INSTDIR\test.bmp
	Delete $INSTDIR\foo.exe
SectionEnd
Schon besser.
Das waren eigentlich schon die grundlegenden Befehle für den NSIS – einfache Installer für Scripte und Mods lassen sich so schon schreiben. Was jetzt kommt, sind die Feinheiten:

Mehrsprachige Installer
Um einen Installer vollständig mehrsprachig zu machen, sind einige Änderungen nötig:
Zuerst einmal werden die gewünschten Sprachen per

Code: Select all

!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "German"
;...
eingebunden. Um dem User beim Start des (Un-)Installers einen Auswahldialog anzuzeigen, müssen die onInit-Funktionen bearbeitet werden:

Code: Select all

Function .onInit
  !insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
Function un.onInit
  !insertmacro MUI_UNGETLANGUAGE
FunctionEnd
Damit wird beim Start des (Un-)Installers ein Auswahldialog angezeigt.
Das ist allerdings noch nicht alles, damit sind naturgemäß nur die „normalen“ Texte des Installers übersetzt. Um die Komponentennamen (und -beschreibungen) zu übersetzen, müssen diese als übersetzbare Strings eingebaut werden. Übersetzbare Strings sind Variablen, die per $(Name) eingesetzt und per „LangString“ übersetzt werden:

Code: Select all

Section $(example) Example
	;...
SectionEnd
LangString example ${LANG_GERMAN} "Beispiel-Sektion"
LangString example ${LANG_ENGLISH} "Example Section"
LangString DESC_ex ${LANG_GERMAN} "Dies ist eine Beispielsektion."
LangString DESC_ex ${LANG_ENGLISH} "This is an example section."
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
	!insertmacro MUI_DESCRIPTION_TEXT ${Example} $(DESC_ex)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Hiermit wird sowohl der Name als auch die Beschreibung der Sektion in der jeweils aktuellen Sprache angezeigt – neben Englisch und Deutsch lassen sich natürlich noch beliebig weitere Sprachen ergänzen.

Integration in die Systemsteuerung und zusätzliche Dateiattribute
Um in der Systemsteuerung angezeigt zu werden, muss der Installer etliche Registry-Keys setzen:

Code: Select all

 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"DisplayName" "<Name>" ;angezeigter Name
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"UninstallString" "$INSTDIR\<Pfad zum Uninstaller>"
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"InstallLocation" "$INSTDIR"
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"Publisher" "<euer Name>"
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"HelpLink" "<URL>"
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"DisplayVersion" "<Version>"
 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"NoModify" 1 ; Keine nachträgliche Modifizierung möglich
 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"NoRepair" 1 ; Keine Reparatur möglich
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"ParentDisplayName" "X3 Terran Conflict v1.0.1" ; Lässt den Mod als Update zu TC erscheinen
 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\<Name>" \
	"ParentKeyName" "X3TerranConflict_is1" ; Lässt den Mod als Update zu TC erscheinen
DisplayName etc. lassen sich auch wieder per LangString übersetzen. Es müssen nicht alle Optionen verwendet werden, alle anzugeben schadet allerdings nicht.
Der NSIS bietet zudem die Möglichkeit, beim Installer zusätzliche Dateiattribute wie die Version zu setzen. Das ist größtenteils Spielerei, aber bspw. die Angabe der Version kann ganz hilfreich sein:

Code: Select all

VIProductVersion <Version>
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "<Name>"
VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "<euer Name>"
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalTrademarks" "X³ Terran Conflict is a registered trademark of EGOSOFT. All rights reserved. <etc. pp.>"
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "<Version>"
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "<Beschreibung>"
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "© <Copyright>"
Hier werden keine LangStrings eingesetzt, sondern direkt die Sprache ausgewählt. Aufpassen.

Automatisch die passenden cat/dat-Nummern auswählen
Diese Funktion ist für Fakepatches extrem praktisch, da hiermit die Nummern der Cats/Dats dynamisch bei der Installation festgelegt werden, wodurch es nicht zu unfreiwilligen Überschreibungen kommt. Dafür braucht ihr folgenden Codeschnipsel:

Code: Select all

!include LogicLib.nsh

Function .onInit
  ;Variable catnumber definieren
  Var /GLOBAL catnum
  StrCpy $catnum 6
  Var /GLOBAL catcnt
  ; ...
FunctionEnd

Function catnums
 ${If} $catnum > 9
	IfFileExists $INSTDIR\$catnum.cat 0 +3 ; Prüft die Katalognummern durch
	  IntOp $catnum $catnum + 1
	  Goto -2
 ${Else}
	IfFileExists $INSTDIR\0$catnum.cat 0 +3 ; Prüft die Katalognummern durch
	  IntOp $catnum $catnum + 1
	  Goto -2
 ${EndIf}
 IntOp $catcnt $catcnt + 1
FunctionEnd

Function SecDone
 FileOpen $1 $INSTDIR\<Name eures Logfiles, sollte eindeutig und nur einmal vergeben sein> a
 FileWrite $1 $catnum
 FileWrite $1 "$\n"
 FileWrite $1 $catcnt
 FileClose $1
FunctionEnd

Section "Uninstall" ;deinstallieren
 FileOpen $1 $INSTDIR\<Name eures Logfiles> r
 FileRead $1 $2 ;höchste Cat-Nummer
 FileRead $1 $3 ;Catanzahl
 FileClose $1
 
 IntOp $2 $2 + 1
 IntOp $3 $3 + 1

 ${While} $3 > 0
  ${If} $2 > 9
   Delete $INSTDIR\$2.cat
   Delete $INSTDIR\$2.dat
  ${Else}
   Delete $INSTDIR\0$2.cat
   Delete $INSTDIR\0$2.dat
  ${EndIf}
  IntOp $3 $3 - 1
  IntOp $2 $2 - 1
 ${EndWhile}
 SectionEnd
Hiermit wird die aktuelle Cat-Nummer global festgelegt (bei TC mit Patch 1.5 ist 06 die erste freie Cat-Nummer). Die höchste Catnummer und die Anzahl der Cats wird gespeichert. Bei der Deinstallation werden, von der höchsten verwendeten Cat-Zahl an, so viele Cats gelöscht wie verwendet – sofern zwischendurch keine Dateien überschrieben wurden, ein sicheres Verfahren.
Damit eure Cats auch umbenannt werden, müssen eure Sections in der folgenden Art aufgebaut sein:

Code: Select all

Section Foo
 SetOutPath $INSTDIR
 Call catnums

 File <Name>.cat
 File <Name>.dat
 ${If} $catnum > 9
   Rename $INSTDIR\<Name>.cat $INSTDIR\$catnum.cat
   Rename $INSTDIR\<Name>.dat $INSTDIR\$catnum.dat
 ${Else}
   Rename $INSTDIR\<Name>.cat $INSTDIR\0$catnum.cat
   Rename $INSTDIR\<Name>.dat $INSTDIR\0$catnum.dat
 ${EndIf}

 Call SecDone
SectionEnd
Eue Cats/Dats dürfen keine Nummern als Namen haben, sonst gibt es Probleme. Der Call am Anfang der Sektion sucht die nächste freie Nummer, dann wird die Datei kopiert und darin umbenannt. Am Schluss wird alles ins Logfile geschrieben, damit der Installer weiß was er löschen muss. Das Vorgehen ist nicht perfekt, aber ausreichend, solange niemand von Hand wahllos cats/dats löscht und hinzufügt. *g*

Schlusswort
Dieses Tutorial soll nicht sämtliche Feinheiten des NSIS erläutern, sondern nur einen Überblick geben, was damit alles möglich ist. Ich hoffe, ich konnte den einen oder anderen dazu bringen, sich etwas mehr mit dem Thema auseinander zu setzen. Auf dass wir bald Mods mit vernünftigen Installern haben. *g*
Für weiterführende Informationen verweise ich auf das Developer Center, das etliche Tutorials und Beispiele bereitstellt: http://nsis.sourceforge.net/Developer_Center

Fragen, Anmerkungen, Kommentare? :)

Post Reply

Return to “X³: Terran Conflict / Albion Prelude - Scripts und Modding”