Poprzedni | Spis treści | Następny

2. Poradnik: Podstawy

Ten dokument zgodny jest z NSIS 3.04


2.1 Wprowadzenie


Większość pakietów oprogramowania, które pobrałeś poprzez internet lub zakupiłeś rozprowadzane są z instalatorem. Instalator kopiuje i/lub uaktualnia pliki, zapisuje klucze rejestru, zapisuje konfigurację, tworzy skróty, itp. Wszystko to dzieje się automatycznie. Użytkownik jedynie powinien dostarczyć kilku informacji, resztą zajmuje się instalator. Użytkownik prowadzony jest przez kreatora instalacji, dokonując odpowiednich wyborów, następnie czeka na zakończenie procesu instalacji. Po zakończeniu instalacji użytkownikowi pozostaje tylko uruchomić zainstalowany program. Użytkownik nie musi martwić się rzeczami, o których mógł zapomnieć, ponieważ wszystkie wymagane operacje przeprowadził instalator.

NSIS jest narzędziem dla programistów do tworzenia właśnie takich instalatorów. NSIS pozwala na stworzenie wszystkiego, poczynając na prostym instalatorze, którego zadaniem jest tylko skopiowanie plików, kończąc na zaawansowanych instalatorach, które obsługują mnóstwo zaawansowanych zadań, takich jak zapis kluczy do rejestru, ustawianie zmiennych środowiskowych, pobieranie najbardziej aktualnych plików z internetu, dostosowywanie plików konfiguracyjnych i więcej. NSIS jest narzędziem bardzo elastycznym, a używany język skryptowy jest łatwy do nauczenia.

NSIS kompiluje wszystkie pliki wraz ze skryptem instalatora do jednego pliku wykonywalnego, co pozwala na łatwą dystrybucję aplikacji. Dodaje tylko około 34KB własnego kodu (przy domyślnej konfiguracji) do danych. Może pochwalić się też najmniejszym dostępnym nagłówkiem, który mimo to dostarcza mnóstwa opcji, dzięki potężnemu językowi skryptowemu i wsparciu dla zewnętrznych wtyczek.

2.2 Pliki skryptów


Aby utworzyć instalator NSIS trzeba najpierw napisać skrypt NSIS. Skrypt taki jest zwykłym plikiem tekstowym ze specjalną składnią. Możesz edytować skrypty w dowolnym edytorze tekstu. Zaleca się jednak używanie edytorów, które pokazują numery linii, jako że NSIS używa ich do informowania, w której linii znajduje się błąd i ostrzega gdzie takie błędy mogą wystąpić. Zalecany jest również edytor, który obsługuje podświetlanie składni. Ze strony NSIS Wiki możesz pobrać edytory stworzone specjalnie dla NSIS i plików z kolorowaniem składni.

W skrypcie NSIS każda linia traktowana jest jako polecenie. Jeśli takie polecenie jest zbyt długie, możesz użyć znaku back-slash - '\' - na końcu linii. Kompilator potraktuje wtedy nową linię jako łańcuch znaków dalszy poprzedniej i nie będzie oczekiwał nowego polecenia. Na przykład:

Messagebox MB_OK|MB_ICONINFORMATION \
"To jest przykład, który pokazuje jak używać łamania linii dla dłuższych poleceń w skryptach NSIS"

Jeśli chcesz używać znaków cudzysłowia w łańcuchu znaków możesz zamiast niego użyć $\" lub użyć innego typu znaku, jak na przykład ` lub '.

Więcej szczegółów o formacie skryptów znajdziesz tutaj: Format pliku skryptu.

Domyślnym rozszerzeniem dla pliku skryptu jest .nsi. Nagłówki plików mają rozszerzenie .nsh. Pliki nagłówkowe mogą pomóc w uporządkowaniu skryptu, dzieląc go na więcej niż jeden blok kodu, pozwalając jednocześnie na dołączenie umieszczonych tam funkcji lub makr do wielu instalatorów. Sprawia to, że aktualizacje skryptów są prostsze, a ich czytanie jest łatwiejsze. Aby dodać plik nagłówkowy do skryptu należy użyć dyrektywy !include. Pliki nagłówkowe, które znajdują się w katalogu Include zainstalowanego NSIS mogą być dołączane poprzez ich nazwę. Na przykład:

!include Sections.nsh

2.3 Struktura skryptów


Skrypt NSIS zawiera atrybuty instalatora, strony oraz sekcje/funkcje. Możesz również użyć poleceń kompilatora w operacjach przy kompilacji. Wymagana jest instrukcja OutFile, która informuje NSIS gdzie zapisać instalatora. Wymagana jest też przynajmniej jedna sekcja.


2.3.1 Atrybuty instalatora


Atrybuty instalatora określają zachowanie i wygląd instalatora. Używając tych atrybutów możesz zmieniać teksty, które pokazywane będą podczas instalacji, liczbę typów instalacji itp. Większość z tych poleceń mogą być tylko ustawione i nie mogą być zmieniane podczas wykonania.

Innymi podstawowymi instrukcjami są Name oraz InstallDir.

Więcej informacji o atrybutach instalatora znajdziesz tutaj: Atrybuty instalatora.



2.3.2 Strony


Instalatory okienkowe są zbiorem stron kreatora, pozwalających użytkownikowi skonfigurować instalatora. Możesz zdecydować, które ze stron wyświetlić używając polecenia Page (lub PageEx w przypadku zaawansowanych ustawień). Typowy zbiór stron wygląda jak poniżej:

Page license
Page components
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles

W instalatorze, ten typowy zbiór stron wyświetli postanowienia licencji, wybór komponentów do zainstalowania, wybór katalogu docelowego instalacji oraz na końcu instalowanie wybranych komponentów na stronie instalacji plików. Dla deinstalatora, wyświetlona zostanie strona potwierdzająca deinstalację oraz strona postępu deinstalacji.



2.3.3 Sekcje


Instalatory zazwyczaj zawierają kilka komponentów, które użytkownik może zainstalować. Dla przykładu, w instalatorze dystrybucji NSIS możesz wybrać instalację dodatkowych narzędzi, wtyczek, przykładów i więcej. Każdy z tych komponentów odzwierciedlany jest przez część kodu. Jeśli użytkownik zaznaczy instalację tego komponentu, instalator wykona ten fragment kodu. W skrypcie, ten kod definiowany jest w sekcjach. Każda sekcja odpowiada jednemu komponentowi na stronie komponentów. Nazwy sekcji wyświetlane są jako nazwy wybranych komponentów, a kod sekcji zostanie wykonany tylko wtedy gdy dany komponent zostanie wybrany. Możliwym jest zbudowanie instalatora z tylko jedną sekcją, lecz jeśli chcesz wykorzystać stronę komponentów i dać możliwość wyboru użytkownikowi co chce zainstalować, będziesz musiał użyć więcej niż jednej sekcji.

Deinstalatory również mogą mieć wiele sekcji. Nazwy sekcji deinstalatora są poprzedzane przez 'un.'. Na przykład:

Section "Sekcja instalatora"
SectionEnd

Section "un.Sekcja deinstalatora"
SectionEnd

Instrukcje, które mogą być użyte w sekcjach różnią się od instrukcji atrybutów instalatora, wykonywane są one na komputerze użytkownika podczas wykonania. Instrukcje te mogą wyodrębniać pliki, czytać i zapisywać dane rejestru, plików INI lub normalnych plików, tworzyć katalogi, tworzyć skróty i wiele więcej. Więcej możesz dowiedzieć się tutaj: Instrukcje.

Najbardziej podstawowymi instrukcjami są instrukcja SetOutPath, która informuje instalator, gdzie ma wyodrębnić pliki oraz instrukcja File, która wyodrębnia pliki.

Przykład:

Section "Mój program"
  SetOutPath $INSTDIR
  File "Mój program.exe"
  File "CzytajMnie.txt"
SectionEnd

Więcej informacji o sekcjach znajdziesz tutaj: Sekcje.



2.3.4 Funkcje


Funkcje mogą zawierać kod skryptu, tak samo jak sekcje. Różnica pomiędzy sekcjami oraz funkcjami polega na sposobie ich wywoływania. Istnieją dwa rodzaje funkcji, funkcje użytkownika oraz funkcje zwrotne.

Funkcje użytkownika wywoływane są przez użytkownika z sekcji lub innych funkcji przy użyciu instrukcji Call. Funkcje użytkownika nie zostaną wykonane dopóki ich nie wywołasz. Po wykonaniu kodu funkcji instalator będzie kontynuował wykonywanie instrukcji znajdujących się po instrukcji Call, chyba że przerwiesz instalację wewnątrz funkcji. Funkcje użytkownika są bardzo użyteczne, jeśli masz wiele instrukcji, które muszą być wykonane w różnych miejscach instalatora. Jeśli wstawisz kod do funkcji oszczędzisz czas na kopiowaniu tego kodu oraz uczynisz go bardziej czytelnym.

Funkcje zwrotne są wywoływane przez instalator podczas zdefiniowanych zdarzeń instalatora, takich jak uruchomienie instalatora. Funkcje zwrotne są opcjonalne. Jeśli, na przykład, chcesz powitać użytkownika swojego instalatora możesz zdefiniować funkcję .onInit. Kompilator NSIS rozpozna tę funkcję jako funkcję zwrotną po nazwie i wywoła ją podczas uruchamiania instalatora.

Function .onInit
  MessageBox MB_YESNO "Ten program zainstaluje Mój program. Czy chcesz kontynuować?" IDYES gogogo
    Abort
  gogogo:
FunctionEnd

Funkcja Abort ma specjalne znaczenie w funkcjach zwrotnych. Każda funkcja zwrotna ma swoją własną interpretację tej funkcji, więcej informacji znajdziesz tutaj: Funkcje zwrotne. W powyższym przykładzie instrukcja Abort instruuje instalatora, by zatrzymał inicjalizację instalatora i zakończył natychmiast działanie.

Więcej informacji o funkcjach znajdziesz tutaj: Funkcje.



2.3.5 Praca ze skryptami



2.3.5.1 Struktury logiczne kodu


Warunkowe wykonywanie kodu lub wykonywanie kodu w pętli może być zrealizowane poprzez użycie instrukcji StrCmp, IntCmp, IfErrors, Goto i innych. Istnieje jednak prostszy sposób. LogicLib udostępnia bardzo proste makra, które umożliwiają skonstruowanie prostych konstrukcji kompletnych struktur logicznych. Składnia, wyjaśniona w pliku nagłówkowym Include/LogicLib.nsh, jest podobna do innych języków programowania i jest prostsza dla użytkowników początkujących jak i tych zaawansowanych.

Dla przykładu, sprawdzanie wartości zmiennej bez użycia LogicLib może być zrealizowane następująco.

StrCmp $0 'jakaś wartość' 0 +3
  MessageBox MB_OK '$$0 jest jakąś wartością'
  Goto done
StrCmp $0 'jakaś inna wartość' 0 +3
  MessageBox MB_OK '$$0 jest jakąś inną wartością'
  Goto done
# else
  MessageBox MB_OK '$$0 jest "$0"'
done:

Jednak, używając LogicLib, kod staje się o wiele bardziej czytelny i prostszy do zrozumienia, jak pokazano na poniższym przykładzie.

${If} $0 == 'jakaś wartość'
  MessageBox MB_OK '$$0 jest jakąś wartością'
${ElseIf} $0 == 'jakaś inna wartość'
  MessageBox MB_OK '$$0 jest jakąś inną wartością'
${Else}
  MessageBox MB_OK '$$0 jest "$0"'
${EndIf}

To samo może być również zrealizowane używając instrukcji Switch, jak pokazano na przykładzie.

${Switch} $0
   ${Case} 'jakaś wartość'
      MessageBox MB_OK '$$0 jest jakąś wartością'
    ${Break}
   ${Case} 'jakaś inna wartość'
      MessageBox MB_OK '$$0 jest jakąś inną wartością'
    ${Break}
   ${Default}
      MessageBox MB_OK '$$0 jest "$0"'
    ${Break}
${EndSwitch}

Wielokrotne warunki również są obsługiwane. Poniższy przykład powiadomi użytkownika, jeśli $0 oraz $1 są puste.

${If} $0 == ''
${AndIf} $1 == ''
  MessageBox MB_OK|MB_ICONSTOP 'Obydwa są puste!'
${EndIf}

LogicLib eliminuje konieczność używania etykiet i skoków warunkowych, co chroni przed konfliktami nazw oraz usuwa konieczność ręcznego poprawiania wielkości skoku warunkowego, za każdym razem gdy zmieni się zawartość skryptu.

Ułatwia również korzystanie z pętli, dzięki wsparciu pętli while, do oraz for. Wszystkie z poniższych przykładów odliczają do pięciu (5) używając LogicLib.

StrCpy $R1 0
${While} $R1 < 5
  IntOp $R1 $R1 + 1
  DetailPrint $R1
${EndWhile}
${For} $R1 1 5
  DetailPrint $R1
${Next}
StrCpy $R1 0
${Do}
  IntOp $R1 $R1 + 1
  DetailPrint $R1
${LoopUntil} $R1 >= 5

Aby móc użyć LogicLib, poniższa linia musi być wstawiona na początku skryptu.

!include LogicLib.nsh

Więcej przykładów można znaleźć w pliku Examples/LogicLib.nsi.



2.3.5.2 Zmienne


Możesz zadeklarować własne zmienne ($VARNAME) poleceniem Var. Zmienne te są zmiennymi globalnymi i mogą być użyte w dowolnej sekcji lub funkcji.

Deklarowanie i używanie zmiennej użytkownika:

Var BLA ; Deklaracja zmiennej

Section bla

  StrCpy $BLA "123" ; Teraz możesz użyć zmiennej $BLA (do której przypisano wartość "123")

SectionEnd

Dodatkowo istnieje stos (Stack), który może być wykorzystany jako tymczasowy zasobnik danych. Aby mieć dostęp do stosu użyj poleceń Push oraz Pop. Polecenie Push dodaje wartość na stos, zaś polecenie Pop zdejmuje tę wartość i ustawia zmienną.

W kodzie współdzielonym dostępnych jest 20 rejestrów (takie jak $0 oraz $R0). Te statyczne zmienne nie muszą być deklarowane i nie ma ryzyka konfliktu nazw. Jeśli chcesz użyć tych zmiennych w kodzie dzielonym, przechowuj oryginalne wartości na stosie i następnie przywracaj te oryginalne wartości.

Po wywołaniu funkcji, zmienne przechowują te same wartości co wcześniej. Zwróć uwagę na ich kolejność, gdy używasz wielu tych zmiennych (last-in first-out, co oznacza że ostatnia odłożona na stos wartość musi być pobrana jako pierwsza):

Function bla

  Push $R0
  Push $R1

    ...kod...

  Pop $R1
  Pop $R0

FunctionEnd


2.3.5.3 Debugowanie skryptów


Im więcej pracujesz w NSIS tym bardziej złożonymi staną się Twoje skrypty. Zwiększy to prawdopodobieństwo pomyłek, zwłaszcza w przypadku używania dużej ilości zmiennych. Istnieje kilka sposobów pomagających w debugowaniu kodu. Aby wyświetlić zawartość zmiennych powinieneś użyć polecenia MessageBox lub DetailPrint. Aby uzyskać informację całościową o wszystkich zmiennych powinieneś użyć wtyczki DumpState. Domyślnie, wszystkie działania instalatora są wyświetlane w oknie dziennika. Informacje z dziennika możesz pobrać klikając prawym klawiszem myszy w oknie dziennika i wybierając opcję "Kopiuj szczegóły do schowka". Istnieje również możliwość bezpośredniego jego zapisywania do pliku, zobacz tutaj.



2.3.6 Wykonywanie skryptu


Gdy użytkownik uruchomi instalatora lub deinstalatora, strony wyświetlane są w takiej kolejności w jakiej zostały zdefiniowane w skrypcie. Na stronie wyświetlającej postęp instalacji plików (instfiles), sekcje odpowiadające wybranym komponentom, są wykonywane w kolejności ich definicji w skrypcie. Jeśli strona z komponentami nie jest wyświetlana, wykonywane są wszystkie, także te, które nie zostały odznaczone lub w jakiś sposób wyłączone przez skrypt.

Poza kodem w sekcjach, istnieje jeszcze kod w funkcjach zwrotnych. Jeśli są zdefiniowane, mogą zostać wykonane przed kodem sekcji. Na przykład, funkcja zwrotna .onInit jest wykonywana przed wszystkim innym w kodzie skryptu. Istnieją również funkcje wywołań zwrotnych stron, które są wykonywane w określonych momentach procesu wyświetlania strony.



2.3.7 Polecenia kompilatora


Polecenia kompilatora wykonywane są w czasie kompilacji na Twoim komputerze. Mogą one być używane do kompilacji warunkowej, do załączania plików nagłówkowych, do uruchamiania aplikacji, do zmiany katalogu roboczego i innych. Najbardziej powszechnym jest używanie definicji. Definicje są stałymi w czasie kompilacji. Możesz zdefiniować numer wersji swojego produktu i użyć go w skrypcie. Na przykład:

!define VERSION "1.0.3"
Name "Mój Program ${VERSION}"
OutFile "Instalator Mojego programu - ${VERSION}.exe"

Więcej informacji o definicjach znajdziesz tutaj: Kompilacja warunkowa.

Innym powszechnym sposobem użycia są makra. Makra używane są do wstawiania kodu w czasie kompilacji, w zależności od definicji oraz wartości tych definicji. Polecenia makr wstawiane są w czasie kompilacji. Pozwala to na zapisanie kodu ogólnego tyko raz i użycie go wiele razy, ale z pewnymi zmianami. Na przykład:

!macro MojaFunkcja UN
Function ${UN}MojaFunkcja
  Call ${UN}DoRegStuff
  ReadRegStr $0 HKLM 'Software\Mój Program' Klucz
  DetailPrint $0
FunctionEnd
!macroend

!insertmacro MojaFunkcja ""
!insertmacro MojaFunkcja "un."

Makro to pomaga uniknąć sytuacji pisania tego samego kodu zarówno dla instalatora jak i deinstalatora. Dwa polecenia !insertmacro wstawiają dwie funkcje, jedną dla instalatora, o nazwie MojaFunkcja oraz drugą dla deinstalatora, o nazwie un.MojaFunkcja. Obie robią dokładnie to samo.

Więcej informacji znajdziesz tutaj: Polecenia przy kompilacji.

2.4 Kompilator


Drugą rzeczą jaką musisz zrobić po napisaniu skryptu, aby stworzyć instalatora, jest skompilowanie skryptu projektu. MakeNSIS.exe jest kompilatorem NSIS. Odczytuje on twój skrypt, przetwarza go i tworzy dla ciebie instalatora.

Aby skompilować skrypt, kliknij prawym klawiszem myszy na pliku .nsi i wybierz Kompiluj skrypt NSIS. Spowoduje to, że MakeNSISW - Interfejs kompilatora NSIS - uruchomi program MakeNSIS, który skompiluje twój skrypt. MakeNSISW pobierze wyjście od MakeNSIS i wyświetli je w oknie, gdzie możesz je zobaczyć, skopiować, przetestować instalatora i więcej. Możliwe jest też użycie kompilatora makensis.exe z wiersza poleceń.

Kompilator sprawdzi twój skrypt i gdy zajdzie taka potrzeba wyświetli informacje o błędach lub ostrzeżeniach. Jeśli wystąpią błędy (np. wymagane są 2 parametry, a podano tylko 1) kompilator przerwie działanie i wyświetli krótki komunikat o błędzie oraz wskaże linię, w której błąd wystąpił. Jeśli błąd nie jest krytyczny kompilator wyświetla ostrzeżenie (np. dwa polecenia DirText w jednym skrypcie). Jeśli skrypt nie ma błędów kompilator wygeneruje na wyjściu instalator, który możesz rozprowadzać.

NSIS obsługuje różne metody kompresji, jak wyjaśnione jest tutaj. Metoda ZLIB jest domyślną metodą kompresji, szybką i zużywającą małą ilość pamięci. Metoda LZMA jest dobrą metodą w tworzeniu małych instalatorów dla dystrubucji sieciowych. Metoda BZIP2 zazwyczaj kompresuje lepiej niż metoda ZLIB, lecz nie tak dobrze jak metoda LZMA. Użyteczna jest, jeśli oczekujesz niskiego zapotrzebowania na pamięć lub szybką kompilację skryptu.

Możliwa jest też kompilacja instalatorów Windows na platformie Linux, BSD lub Mac OS X. Więcej szczegółów znajdziesz tutaj: Kompilacja NSIS.

2.5 Nowoczesny Interfejs Użytkownika (Modern UI)


Popularnym interfejsem użytkownika dla NSIS jest Nowoczesny Interfejs Użytkownika (Modern User Interface). Jest interfejsem zgodnym ze stylem kreatorów ostatnich wersji Windows. Interfejs ten nie jest tylko plikiem zasobów, który można zmieniać, posiada mnóstwo nowych elementów interfejsu. Posiada obszar nagłówka w kolorze białym, który opisuje aktualny postęp instalacji, obszar opisowy na stronie wyboru komponentów, stronę początkową, stronę końcową, która umożliwia użytkownikowi na uruchomienie aplikacji lub ponowne uruchomienie komputera i więcej.

Więcej informacji znajdziesz w pliku Nowoczesny Interfejs Użytkownika oraz przykładach z katalogu Examples zainstalowanego NSIS.

2.6 Wtyczki


NSIS obsługuje wtyczki, które mogą być wywoływane poprzez skrypt. Wtyczki są bibliotekami DLL napisanymi w języku C, C++, Delphi lub innym języku programowania. Wtyczki rozszerzają możliwości kodu NSIS.

Więcej o wtyczkach dowiesz się w tym dokumencie.

2.7 Więcej


Ten poradnik opisał podstawowe możliwości NSIS. Aby dowiedzieć się więcej o tym co potrafi NSIS musisz znaleźć troszkę więcej czasu na przeczytanie całej dokumentacji.