|
Lab #0 |
| Labs come at the end of each part of this article. In each lab we will examine a bit more than what we talked about in that part. In the final lab, we will have a complete setup application. | |
It's not quiet bad, but it's much better to have an IDE, isn't it? The second link above
refers to a good yet small IDE for NSIS called "HM NIS Edit".
In NSIS Developer center you can download other IDE's or integrations to
current Editors like Eclipse. Link to available text editors page is:
http://nsis.sourceforge.net/Category:Development_Environmentsnmen
In HM editor we can also compile and run our installers, without the need to exit the IDE.
We have a wizard, a page designer, and also F1 launches NSIS Script chm help
file.
After running the IDE, you can either type in
commands or use the wizard to craete a template for a simple installer.
Personally I didn't learn using NSIS scripts until I started creating my own
instructions, from scratch.
Understanding pages and sections is quiet easy, since they represent visual equivalent
in the final compiled installer. The above script, if compiled, will produce the following
installer:
Name "MyProduct Version 1.0"
The following table lists some of the useful attributes that you can use in your script:
| Attributes | What it does |
| Name | Sets the name of the installer. |
| OutFile | Specifies the output file that the MakeNSIS should write the installer to. Name of the installer file(like MySetup.exe) |
| InstallDir | Sets the default installation directory. |
| ShowInstDetails | Sets whether or not the details of the install are shown. |
| ShowUnInstDetails | Sets whether or not the details of the uninstall are shown. |
| SetCompressor | Sets the compression algorithm used to compress files/data in the installer. |
| SetCompressorDictSize | Sets the dictionary size in megabytes (MB) used by the LZMA compressor. |
|
Lab #1 |
|
Using HM NIS Edit create a new nsi script file. type the folloeing
lines into it.
!include "LogicLib.nsh"
In NSIS script, we can add macros (lines started with !include "MUI2.nsh" !define PRODUCT_NAME "CP Lab" !define SETUP_NAME "CPLabSetup.exe" !define PRODUCT_VERSION "1.0" OutFile ${SETUP_NAME} Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" ;Default installation folder InstallDir "$PROGRAMFILES\CPLab"   ;Get installation folder from registry if available InstallDirRegKey HKLM "Software\CP Lab" ""   ShowInstDetails show ShowUnInstDetails show SetCompressor /SOLID lzma SetCompressorDictSize 12 ;Request application privileges for Windows Vista RequestExecutionLevel user ;Could be 'admin' !define
)and also we can use scripts in another files, using
!include compile time command.
.nsh files contains normal NSIS Scripts, just like our script. The only
difference is that we put .nsi to compile our script, but to include another one
we have to give that file .nsh extension.
Please note that when using macros, we need to use both $ sign and
{} while in variables it was just the $ sign.
|
|
var command. To
use it, we must use a $ before
variable name:
var varName
...
StrCpy $varName "example value"
Notes when using variables:
Predefined variables: There are some variables that already defined in NSIS and we can use them without declaration. Also we must be careful and prevent from possible conflicts in our names with these:
$0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $R0, $R1, $R2, $R3, $R4, $R5, $R6, $R7, $R8, $R9
NSIS sometimes refers to these variables as registers.
$INSTDIR: The installation directory. Can be used anywhere
in your script and will be replaced by the installation directory path at
runtime. This variable already set by you when using InstallDir attribute, but
at runtime user is able to change it. You can also modify this variable using
StrCpy command. $OUTDIR: The current output directory. SetOutPath
or StrCpy could be used to set this variable.
Constants: Here's a good place to name some of the useful constants that NSIS defined for us. They also added these to their variable part of the help. Remember
InstallDir attribute? If you don't it was the attribute that mean to
set installation directory for us. Unless you are sure about where you want your installer
files to be copied exactly (like C:\MyFolder), you'll need to know some paths like
Windows folder path or program files folder path.
Constants help you here. At runtime they will be replaced with end user computer paths. Please look at the following example:
InstallDir "$PROGRAMFILES\MyApp"
Here we used $PROGRAMFILES constant in front of the InstallDir which expected an string.
$PROGRAMFILES will be replaced by the exact path string on users' computer.
The following table shows a list of useful constants:
| Constant | What it means |
| $PROGRAMFILES | Usually C:\ program files but may be different on different machines |
| $PROGRAMFILES32, $PROGRAMFILES64 | On Windows X64, first one points to C:\Program Files (x86) while the second points to C:\Program Files |
| $DESKTOP | The Windows desktop directory (usually C:\Windows\Desktop but detected at runtime). |
| $EXEDIR | The directory containing the installer executable. |
| $EXEPATH | The full path of the installer executable. |
| ${NSISDIR} | A symbol that contains the path where NSIS is installed. Useful if you want to call resources that are in NSIS directory e.g. Icons, UIs etc. |
| $WINDIR | The Windows director |
| $SYSDIR | The Windows system directory |
| $TEMP | The system temporary directory |
| $STARTMENU | The start menu folder (useful in adding start menu items using CreateShortCut). |
| $SMSTARTUP | The start menu programs / startup folder. The context of this constant (All Users or Current user) depends on the SetShellVarContext setting. The default is the current user. |
| $DOCUMENTS | The documents directory. The context of this constant (All Users or Current user) depends on the SetShellVarContext setting. The default is the current user. |
| $APPDATA | The application data directory. The context of this constant (All Users or Current user) depends on the SetShellVarContext setting. The default is the current user. |
| $CDBURN_AREA | A directory where files awaiting to be burned to CD are stored. This constant is available on Windows XP and above. |
Section "Installer"
; Instructions go here
SectionEnd
In the above example, I created a new section and named that 'Installer' (Don't let the name fool you, it's just a name. you can put it MySec if you want.)
|
Lab #2 |
|
Reload previous file into your editor and add the following:
Section "Dummy Section" SecDummy
The above code creates two section. We want the first one to be visible.
The Second section above will be called when uninstalling. NSIS Compiler
realizes that because of the name. If a section name is 'UnInstall'
or it starts with 'un.' it will be called when uninstalling.
SetOutPath "$INSTDIR" ;Store installation folder WriteRegStr HKCU "Software\CP Lab" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" SectionEnd Section "Uninstall" Delete "$INSTDIR\Uninstall.exe" RMDir "$INSTDIR" DeleteRegKey /ifempty HKCU "Software\CP Lab" SectionEnd WARNING:Please note that calling RMDir to remove our app folder is really DANGEROUS.
The reason is quiet simple. Think about a beginner user that changes default folder path to C:\Program Files.
You save path when installing and uppon calling RMDir installer
tries removing the whole program files folder.
|
|
Call instruction.
"Callback functions will be called by the installer when a certain event occurs."
"Functions must be declared outside of Sections or other Functions."
Function func
; some commands
FunctionEnd
Section
Call func
SectionEnd
The above code shows how to create a user function. There is also another type of function
called callback. Callback functions are known by their names. The names are unique and the
NSIS compiler can recognize them. These functions will be called upon special events and
you're free to put your favorite instructions in them, so that upon the event, they'll run.
Function .onInit
MessageBox MB_YESNO "This will install. Continue?" IDYES NoAbort
Abort ; causes installer to quit.
NoAbort:
FunctionEnd
The above code shows how to write .onInit so that as soon as the installer
starts, a message box asks user if he/she is interested to continue.
The following table lists some of the common Callback functions.
| Callback function name | When it's called |
| .onInit | Will be called when the installer is nearly finished initializing. If the '.onInit' function calls Abort, the installer will quit instantly. |
| .onUserAbort | Is called when the user hits the 'cancel' button, and the install hasn't already failed. If this function calls Abort, the install will not be aborted. |
| .onInstFailed | Is called when the user hits the 'cancel' button after the install has failed. |
| .onMouseOverSection | is called whenever the mouse position over the sections tree has changed. This allows you to set a description for each section for example. The section id on which the mouse is over currently is stored, temporarily, in $0. |
| un.onInit | Will be called when the uninstaller is nearly finished initializing. If the 'un.onInit' function calls Abort, the uninstaller will quit instantly. |
|
Lab #3 |
|
Let's add two functions to our installer. A callback and a user one.
Function .OnInit
Here we create a callback function .onInit that will be called whenever the installer
starts up, before pages being shown. Then we copy a message into StrCpy $0 "Welcome to my first setup wizard" push $0 Call ShowWelcome FunctionEnd Function ShowWelcome pop $R0 ${If} $R0 == '' StrCpy $R0 "Message from function" ${EndIf} MessageBox MB_OK $R0 FunctionEnd $0 variable
that has already been defined for us by the compiler, and finally push it, so that we can use it in a function
later on. Finally we call a function.
The user function tries to pop a string off the stack and in to $R0 that again has
been defined already by the compiler. We check to make sure it has a value, and if it has not
we put another value into $R0 and we finally show a message box.
This shows how we create functions, pass arguments (using built-in stack), use variables and
how easy it is to use logiclib that we already included. If we were not to use
logiclib we had to write a code similar to IBM x86 assembly instead of that $IF.
|
|
Page license
The above code shows a simple empty license page, to force it to show your license file,
you should use page options. In fact not only the license page, but also all other default
pages have options that can be provided by the help of attributes.
Another way of coding UI is to use modern UI. It's not only simpler but also much familiar and nicer.
Modern UI is included to the NSIS after version 2.0. Documentation to the UI is available here:
http://nsis.sourceforge.net/Docs/Modern%20UI/Readme.html
When I'm writing this article, the second version of modern UI is available with even better
features.
!insertmacro MUI_PAGE_LICENSE "License.rtf"
The above code adds a license page and loads the specified file to be signed by the user.
last important thing in the pages is that they all have events (remember callbacks?) With
these callback handlers you can simply modify the way they behave or decide what to do after
or before a page showed. It's for example, useful when we want to ignore next page or to enable/disable some
options according to previous pages.
!define MUI_PAGE_CUSTOMFUNCTION_PRE PAGE_LICENSE
!insertmacro MUI_PAGE_LICENSE "License.rtf" "" PreLicense
...
Function PreLicense
; If app installed already, license signed, ignore it
${If} $bAppExists == '1'
Abort
;${Else}
${EndIf}
FunctionEnd
The above code calls a function before displaying license page. The function checks a
variable to see if application already exists. If it exists, the license page will be
ignored and next page will be shown.
|
Lab #4 |
|
If we run our installer right now, it will work! It uses sections and
our attributes and also some default behavior to do required operations.
The problem is that there is not any customization available to user.
Let's get user some choices using pages of the modern UI.
!insertmacro MUI_PAGE_WELCOME
Just add some pages, and we're done. Before we finish this lab, please note that how we used
the SecDummy to add a description to the 'select feature' page. If you return back
and take a look at sections, you'll notice that other than the name, there's a SecDummy
at the end of the line. In fact this is called section index and it is used to access
a section.
!insertmacro MUI_PAGE_LICENSE "License.txt" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH   !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH   !insertmacro MUI_LANGUAGE"English"   ;-------------------------------- ;Descriptions   ;Language strings LangString DESC_SecDummy ${LANG_ENGLISH} "A section"   ;Assign language strings to sections !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy) !insertmacro MUI_FUNCTION_DESCRIPTION_END The last 8 lines are there just to show "A section" text when mouse is over the "Dummy Section". |
|
| Instruction | What it does | Usage |
| File | Adds file(s) to be extracted to the current output path ($OUTDIR). | File "Bin\7z\*.*" |
| Quit | Causes the installer to exit as soon as possible. | |
| ExecWait | Execute the specified program and wait for the executed process to quit. | ExecWait 'c:\SomeProgram.exe' $0 |
| DetailPrint | Adds the string "message" to the details view of the installer. | DetailPrint "message" |
| Strlen | Sets user variable $x with the length of str. | Strlen $0 ${SETUP_NAME} |
| ReadRegStr | Reads from the registry into the user variable. | ReadRegStr $0 HKLM Software\NSIS "" |
| CopyFiles | Copies files from the source to the destination on the installing system. | CopyFiles "$0\cid.dll" "$INSTDIR" |
| CreateDirectory | Creates (recursively if necessary) the specified directory. | CreateDirectory "7z" |
| CreateShortCut | Creates a shortcut 'link.lnk' that links to 'target.file', with optional parameters 'parameters'. | CreateShortCut "$SMPROGRAMS\$STMenuDirectory\Help.lnk" "$INSTDIR\Yas.chm" |
| IfFileExists | Checks for existence of file(s). | IfFileExists "$INSTDIR\${SQL_DATABASE_NAME}.mdf" 0 Goon_label |
| Delete | Delete file (which can be a file or wildcard, but should be specified with a full path) from the target system. | Delete '"$INSTDIR\${SQL_DATABASE_NAME}.mdf"' |
| DeleteRegKey | Deletes a registry key. | DeleteRegKey[/ifempty] root_key subkey |
| DeleteRegValue | Deletes a registry value. Valid values for root_key are listed under WriteRegStr. | DeleteRegValue root_key subkey key_name |