Poprzedni | Spis treści | Następny

Dodatek D: Użyteczne Informacje


D.1 Poziomy Błędu

Tak jak inne aplikacje, instalatory stworzone w NSIS zwracają poziomy błędów jako wynik ich wykonania. Sprawdzanie poziomu błędów może być użyteczne, jeśli wywołujesz instalatora NSIS z poziomu innej aplikacji lub instalatora.

  • 0 - Normalne wykonanie (brak błędów)
  • 1 - Instalacja przerwana przez użytkownika (przyciskiem Anuluj)
  • 2 - Instalacja przerwana przez skrypt

Od wersji NSIS 2.01, możesz ustawiać poziom błędów na inne wartości używając funkcji SetErrorLevel.

Zwróć uwagę, że deinstalatory kopiują się do katalogu tymczasowego i tam się wykonują, by oryginalny deinstalator mógł być usunięty. Oznacza to, że poziom błędów deinstalatora nie jest dostępny dla wykonywanego procesu, jeśli nie zasymulujesz tej kopi procesu oraz wykonasz skopiowany deinstalator. Aby zasymulować ten proces, użyj:

CopyFiles $INSTDIR\uninstaller.exe $TEMP
ExecWait '"$TEMP\uninstaller.exe" _?=$INSTDIR' $0
DetailPrint "Poziom błędów deinstalatora: $0"

Jeśli nie wykonasz tych czynności, będziesz mógł jedynie stwierdzić czy udało się poprawnie lub też nie skopiować deinstalatora do katalogu tymczasowego.


D.2 Dodawanie informacji o deinstalacji do systemowego Dodaj/Usuń Programy

Utwórz klucz z nazwą twojego produktu w HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall, aby dodać wpis do sekcji "Dodaj/Usuń Programy" Panelu Sterowania Windows. W Windows NT (NT4/2000/XP), możliwym jest również stworzenie klucza w gałęzi HKCU, co spowoduje, że informacja o programie widoczna będzie tylko dla danego użytkownika. Istnieje kilka wartości, które możesz zapisać do klucza rejestru. Są to informacją o twoim programie i deinstalatorze. Wartości zapisuje się przy użyciu polecenia WriteRegStr (dla łańcuchów znaków) lub polecenia WriteRegDWORD (dla wartości typu DWORD). Na przyklad:

WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Product" "DisplayName" "Nazwa"

Wymagane wartości

DisplayName (łańcuch znaków) - Nazwa aplikacji
UninstallString (łańcuch znaków) - Ścieżka dostępu oraz nazwa pliku deinstalatora. Powinieneś zawsze umieszczać ścieżkę dostępu w cudzysłowiu, by mieć pewność, że znaki spacji nie uniemożliwią systemowi Windows odnalezienia deinstalatora.

Wartości opcjonalne

Niektóre z poniższych wartości nie zostaną wykorzystane przez starsze wersje systemu Windows.

InstallLocation (łańcuch znaków) - Katalog docelowy instalacji ($INSTDIR)
DisplayIcon (łańcuch znaków) - Ścieżka dostępu, nazwa pliku oraz indeks ikony, która zostanie wyświetlona obok nazwy aplikacji

Publisher (łańcuch znaków) - (Firma) nazwa wydawcy

ModifyPath (łańcuch znaków) - Ścieżka dostępu oraz nazwa pliku programu modyfikującego
InstallSource (łańcuch znaków) - Lokalizacja miejsca, z którego zainstalowana została aplikacja

ProductID (łańcuch znaków) - ID produktu aplikacji
RegOwner (łańcuch znaków) - Zarejestrowany użytkownik aplikacji
RegCompany (łańcuch znaków) - Zarejestrowana firma aplikacji

HelpLink (łańcuch znaków) - Łącze do strony ze wsparciem online
HelpTelephone (łańcuch znaków) - Numer telefonu wsparcia technicznego

URLUpdateInfo (łańcuch znaków) - Łącze do strony z uaktualnieniami aplikacji
URLInfoAbout (łańcuch znaków) - Łącze do strony domowej aplikacji

DisplayVersion (łańcuch znaków) - Wyświetlana wersja aplikacji
VersionMajor (DWORD) - Główny numer wersji aplikacji
VersionMinor (DWORD) - Numer podwersji aplikacji

NoModify (DWORD) - 1 jeśli deinstalator nie posiada opcji modyfikowania zainstalowanej aplikacji
NoRepair (DWORD) - 1 jeśli deinstalator nie posiada opcji naprawy instalacji

Jeśli zarówno NoModify jak i NoRepair ustawione są na 1, wyświetlany jest przycisk "Usuń" zamiast "Zmień/Usuń".


D.3 Wywoływanie zewnętrznych bibliotek DLL przy użyciu wtyczki System.dll

Niektóre procesy instalatora wymagają wywoływania funkcji, które znajdują się w zewnętrznych bibliotekach DLL. Świetnym przykładem jest tutaj instalacja Palm(TM).

Trochę informacji o wtyczce System.dll
Wtyczka System.dll (napisana przez Brainsucker) umożliwia wywoływanie funkcji z zewnętrznych bibliotek poprzez użycie funkcji 'Call'. Istnieje mnóstwo innych funkcji obsługiwanych przez wtyczkę System.dll, ale nie będą one tutaj rozpatrywane. Więcej szczegółów o innych funkcjach znajdziesz w podręczniku System.

Typy Danych
System.dll rozpoznaje następujace typy danych:

  • v - void (ogólnie do zwracania wartości)
  • i - int (char, byte, short, uchwyty, wskaźniki i tak dalej)
  • l - long & duży integer (typcałkowity, znany też jako int64)
  • t - tekst, łańcuch znaków (LPCSTR, wskaźnik do pierwszego znaku)
  • b - boolean (wymaga/zwraca 'true':'false') - tak de facto ten typ jest bezsensowny -> zazwyczaj można użyć typu całkowitego integer ('0':'1')
  • k - wywołania zwrotne. Zobacz sekcję wywołania zwrotne (Callback) w pliku system.php.
  • * - wskaźnik -> procedura wymaga wskażnika do typu, działa na następny znak (parametr) [ex: '*i' - wskaźnik do int]

Mapowanie zmiennych System.dll do zmiennych skryptu NSIS
Nie ma wiekszego sensu wywoływanie funkcji z zewnątrz, jeśli nie pobiera się żadnych danych. System.dll mapuje zmienne funkcji do zmiennych skryptu NSIS w następujący sposób:

NSIS $0..$9 stają się System.dll r0..r9 NSIS $R0..$R9 stają się System.dll r10..r19

Każdy parametr określony jest przez swój typ, wejście oraz wyjście. Aby pominąć wejście lub wyjściu użyj kropki. Przykłady:

Łańcuch znaków (wskaźnik na tablicę znaków), wejściem jest 'happy calling':

t 'happy calling'

Łańcuch znaków (wskaźnik na tablicę znaków), wejście jest pobrane z $5, a zmiany w tablicy dokonane przez wywołanie zapisywane są w $R8:

t r5R8

Wskaźnik do typu całkowitego (integer), wartość pobierana z $1 i wstawiana do $2:

*i r1r2

Wskaźnik do 64-bit liczby całkowitej (integer), wyjście odłożone na stos, brak wejścia:

*l .s

Użyj System.dll::Call Aby wywołać funkcję w zewnętrznej bibliotece DLL, funkcja Call używana jest w następujący sposób:

System::Call 'NazwaTwojejBibliotekiDLL::FunkcjaTwojejbibliotekiDll(i, *i, t) i(r0, .r1, r2) .r3'

Sekcja '(r0, .r1, r2) .r3' na końcu jest sekcją parametrów, które przekazywane są pomiędzy twoją biblioteka DLL, a skryptem NSIS. Jak można zauważyć na tej liście parametrów typy oraz wejście/wyjście mogą być rozdzielane. Każdy blok "(lista parametrów) zwraca wartość" nadpisując oraz/lub dodając do ostatniej. W takim przypadku, pierwszy blok określa typy, a kolejny określa wejście oraz wyjście.

Przed przystąpieniem do kodowania skryptu NSIS
Zanim zaczniesz kodować jakikolwiek kod skryptu NSIS, musisz poznać całkowity prototyp funkcji, którą zamierzasz wywołać. Dla celów tego przykładu, użyjemy funkcji 'CmGetHotSyncExecPath' z biblioteki 'CondMgr.dll' Palm. Funkcja ta jest używana do zwrócenia pełnej ścieżki dostępu do pliku 'HotSync.exe'.

Definicja Funkcji

int CmGetHotSyncExecPath(TCHAR *pPath, int *piSize);

wgdzie:

  • pPath jest wskaźnikiem do bufora znaków. Zwracana wartość jest ścieżką & nazwą pliku zainstalowanego menadżera HotSync.
  • piSize jest wskaźnikiem do liczby całkowitej, która określa rozmiar (w TCHAR), bufora odniesionego do parametru pPath.

zwracane wartości:

  • 0: brak błędów
  • -1: Wystąpił nieokreślony błąd
  • ERR_REGISTRY_ACCESS(-1006): Błąd dostępu do wpisów konfiguracji Palm
  • ERR_BUFFER_TOO_SMALL(-1010): Bufor jest zbyt mały, by móc przechować żądane informacje
  • ERR_INVALID_POINTER(-1013): określony wskaźnik nie jest poprawnym wskaźnikiem

Także, jeśli bufor jest zbyt mały wartość w *int jest rozmiarem (w TCHAR), jaki powinien mieć ten bufor.

Ta funkcja definiuje mapowanie na następującą definicję System.dll:

CmGetHotSyncExecPath(t, *i) i

Np. Pobiera tekstową zmienną, wskaźnik do int, i zwraca wartość typu int.

Używanie funkcji z zewnętrznych bibliotek dll
Jak już wiemy, co funkcja robi i w jaki sposób mapuje do formatu System.dll, możemy użyć ją w skrypcie NSIS.

Po pierwsze, zaleca się wyłączenie instrukcji 'PluginUnload' przed próbą wielokrotnego odwoływania się do biblioteki System.dll. Zgodnie z zaleceniami użytkownika Brainsucker (i innych), przyspieszy to wykonanie pakietu instalatora.

Po drugie, musisz zmienic wyjściowy katalog, na ten w którym znajduje się biblioteka DLL, którą chcesz użyć. Może to również działać w przypadku, gdy ta biblioteka DLL znajduje się w ścieżce systemowej, ale nie zostało to przetestowane.

Poniższy fragment kodu zainstaluje bibliotekę 'condmgr.dll' do katalogu tymczasowego, wykona funkcję CmGetHotSyncExecPath, wyświetli zwrócone dane i wreszcie wyładuje z pamięci wtyczkę System.dll. Zapisz ten skrypt.

; **** wycinek ****
SetPluginUnload  alwaysoff

Function loadDll

  SetOutPath $TEMP\eInspect             ; tworzenie katalogu tymczasowego
  File bin\CondMgr.dll                  ; skopiowanie tam biblioteki dll
  StrCpy $1 ${NSIS_MAX_STRLEN}          ; przypisanie pamięci do zmiennej $0
  System::Call 'CondMgr::CmGetHotSyncExecPath(t, *i) i(.r0, r1r1).r2'
  DetailPrint 'Ścieżka dostępu: "$0"'
  DetailPrint "Długość ścieżki dostępu: $1"
  DetailPrint "Zwrócona wartość: $2"

; ostatnie wywołanie wtyczki nie może mieć przełącznika /NOUNLOAD, aby NSIS mógł usunąć
; tę tymczasową bibliotekę DLL

  SetPluginUnload manual
; nie rób nic (ale zezwól instalatorowi na wyładowanie biblioteki System.dll)
  System::Free 0
FunctionEnd
; **** wycinek ****

Powyższa funkcja tworzy wyjście na stronie 'Szczegóły':

Katalog wyjściowy: c:\windows\TEMP\eInspect
Wypakuj: CondMgr.dll
Ścieżka dostępu: "C:\Dave\palm\Hotsync.exe"
Długość ścieżki dostępu: 24
Zwrócona wartość: 0

Napisał djc

Wyrazy uznania & Podziękowania
Podziękowania dla kichik oraz Sunjammer za spędzenie mnóstwa czasu przy asystowaniu w rozwiązywaniu tego problemu. Również dzięki dla brainsucker za stworzenie wtyczki System.dll. Powodzenia!


D.4 Zrzut Zawartości Okna Logu do Pliku

Funkcja ta zrzuci tekst logu instalatora (szczegóły instalacji) do określonego pliku. Stworzyłem tę funkcję dla użytkownika Afrow_UK, który prosił o rozwiązanie problemu zrzutu tekstu logu do pliku w tym wątku forum.

Aby jej użyć, podaj nazwę pliku i wywołaj ją. Zrzuci ona tekst logu do tego określonego pliku. Na przykład:

GetTempFileName $0
Push $0
Call DumpLog

A oto i funkcja:

!define LVM_GETITEMCOUNT 0x1004
!define LVM_GETITEMTEXT 0x102D

Function DumpLog
  Exch $5
  Push $0
  Push $1
  Push $2
  Push $3
  Push $4
  Push $6

  FindWindow $0 "#32770" "" $HWNDPARENT
  GetDlgItem $0 $0 1016
  StrCmp $0 0 error
  FileOpen $5 $5 "w"
  StrCmp $5 0 error
    SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
    System::Alloc ${NSIS_MAX_STRLEN}
    Pop $3
    StrCpy $2 0
    System::Call "*(i, i, i, i, i, i, i, i, i) i (0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
    loop: StrCmp $2 $6 done
      System::Call "User32::SendMessageA(i, i, i, i) i ($0, ${LVM_GETITEMTEXT}, $2, r1)"
      System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
      FileWrite $5 "$4$\r$\n"
      IntOp $2 $2 + 1
      Goto loop
    done:
      FileClose $5
      System::Free $1
      System::Free $3
      Goto exit
  error:
    MessageBox MB_OK error
  exit:
    Pop $6
    Pop $4
    Pop $3
    Pop $2
    Pop $1
    Pop $0
    Exch $5
FunctionEnd

Napisał KiCHiK


D.5 Jak odczytywać Wartości Rejestru REG_MULTI_SZ

Napisałem ten skrypt by pomóc użytkownikowi rpetges w rozwiązaniu problemu opisanego w tym wątku forum. Odczytuje on wartość typu REG_MULTI_SZ z rejestru Windows i wypisuje ją. Pamiętaj, o jego edycji, tam gdzie napisane jest "Edytuj tutaj!" gdy testujesz swój skrypt. Wartości muszą wskazywać na wartość REG_MULTI_SZ, bo w przeciwnym razie przykład wygeneruje błędy.

OutFile "REG_MULTI_SZ Reader.exe"

Name "REG_MULTI_SZ Reader"

ShowInstDetails show

!define HKEY_CLASSES_ROOT        0x80000000
!define HKEY_CURRENT_USER        0x80000001
!define HKEY_LOCAL_MACHINE       0x80000002
!define HKEY_USERS               0x80000003
!define HKEY_PERFORMANCE_DATA    0x80000004
!define HKEY_PERFORMANCE_TEXT    0x80000050
!define HKEY_PERFORMANCE_NLSTEXT 0x80000060
!define HKEY_CURRENT_CONFIG      0x80000005
!define HKEY_DYN_DATA            0x80000006

!define KEY_QUERY_VALUE          0x0001
!define KEY_ENUMERATE_SUB_KEYS   0x0008

!define REG_NONE                 0
!define REG_SZ                   1
!define REG_EXPAND_SZ            2
!define REG_BINARY               3
!define REG_DWORD                4
!define REG_DWORD_LITTLE_ENDIAN  4
!define REG_DWORD_BIG_ENDIAN     5
!define REG_LINK                 6
!define REG_MULTI_SZ             7

!define RegOpenKeyEx     "Advapi32::RegOpenKeyExA(i, t, i, i, i) i"
!define RegQueryValueEx  "Advapi32::RegQueryValueExA(i, t, i, i, i, i) i"
!define RegCloseKey      "Advapi32::RegCloseKeyA(i) i"

####### Edytuj tutaj!

!define ROOT_KEY         ${HKEY_CURRENT_USER}
!define SUB_KEY          "Software\Joe Software"
!define VALUE            "Strings"

####### Koniec edycji

Section "Read"
  StrCpy $0 ""
  StrCpy $1 ""
  StrCpy $2 ""
  StrCpy $3 ""
  SetPluginUnload alwaysoff
  System::Call "*(i) i (0) .r0"
  System::Call "*(i) i (0) .r1"
  System::Call "*(i) i (0) .r2"
  System::Call "${RegOpenKeyEx}(${ROOT_KEY}, '${SUB_KEY}', \
    0, ${KEY_QUERY_VALUE}|${KEY_ENUMERATE_SUB_KEYS}, r0) .r3"

  StrCmp $3 0 goon
    MessageBox MB_OK|MB_ICONSTOP "Nie udało się otworzyć klucza rejestru! ($3)"
    Goto done
goon:

  System::Call "*$0(&i4 .r4)"
  System::Call "${RegQueryValueEx}(r4, '${VALUE}', 0, r1, 0, r2) .r3"

  StrCmp $3 0 read
    MessageBox MB_OK|MB_ICONSTOP "Nie udało się przetworzyć wartości rejestru! ($3)"
    Goto done

read:

  System::Call "*$1(&i4 .r3)"

  StrCmp $3 ${REG_MULTI_SZ} multisz
    MessageBox MB_OK|MB_ICONSTOP "Wartość rejestru nie jest wartością typu SZ_MULTI_SZ! ($3)"
    Goto done

multisz:

  System::Call "*$2(&i4 .r3)"

  StrCmp $3 0 0 multiszalloc
    MessageBox MB_OK|MB_ICONSTOP "Wartość rejestru jest pusta! ($3)"
    Goto done

multiszalloc:

  System::Free $1
  System::Alloc $3
  Pop $1

  StrCmp $1 0 0 multiszget
    MessageBox MB_OK|MB_ICONSTOP "Nie można zaalokować wystarczającej ilości pamięci! ($3)"
    Goto done

multiszget:

  System::Call "${RegQueryValueEx}(r4, '${VALUE}', 0, 0, r1, r2) .r3"

  StrCmp $3 0 multiszprocess
    MessageBox MB_OK|MB_ICONSTOP "Nie udało się przetworzyć wartości rejestru! ($3)[2]"
    Goto done

multiszprocess:

  StrCpy $4 $1

  loop:

    System::Call "*$4(&t${NSIS_MAX_STRLEN} .r3)"
    StrCmp $3 "" done
    DetailPrint $3
    StrLen $5 $3
    IntOp $4 $4 + $5
    IntOp $4 $4 + 1
    Goto loop

done:

  System::Free $2
  System::Free $1

  StrCmp $0 0 noClose
    System::Call "${RegCloseKey}(r0)"

noClose:

  SetPluginUnload manual
  System::Free $0
SectionEnd

Napisał KiCHiK


Poprzedni | Spis treści | Następny

Ostatnia aktualizacja strony: Niedziela, 6 Września 2009 (16:05:25)
Copyright © 2002 - 2010 by Paweł Porwisz. Wszelkie prawa zastrzeżone.
Strona wygenerowana w 0.001s. Hosted by tox.pl
[Valid XHTML] [Valid CSS] [Valid RSS] [Opera] [BrowseHappy]