2.1 Introduction
Most software packages you download or buy come with an installer. The installer copies and/or updates files, writes registry keys, writes configuration, creates shortcuts, etc. All of this is done automatically for the user. All the user needs to do is supply some information and the installer will do the rest. The user goes through a wizard, makes the appropriate choices and waits until the installer finishes. After the installer has finished the user is left only with the simple task of starting the program. The user doesn't have to worry about things he might have forgotten because all of the necessary steps were done by the installer.
NSIS is a tool for developers to create such installers. NSIS allows you to create everything from basic installers that just copies files to very complex installers that handle a lot of advanced tasks such as writing registry keys, settings environment variables, downloading the latest files from the internet, customizing configuration files and more. NSIS is very flexible and its scripting language is easy to learn.
NSIS compiles all of the files and the installation script into one executable file so your application will be easy to distribute. NSIS adds only about 34KB of code of its own (for the default configuration) to the data. NSIS boasts the smallest overhead available while still providing a lot of options thanks to its powerful scripting language and support of external plug-ins.
2.2 Script Files
To create a NSIS installer you first have to write a NSIS script. A NSIS script is just a regular text file with a special syntax. You can edit scripts with any text editor. It's recommended to use a text editor that shows line numbers because NSIS uses line numbers to indicate where errors lie, and to warn you about where errors might lie. An editor that supports syntax highlighting is also recommended. You can download editors made especially for NSIS and files for syntax highlighting from the NSIS Wiki.
In a NSIS script every line is treated as a command. If your command is too long for one line you can use a back-slash - '' - at the end of the line. The compiler will treat the new line as an addition to the previous line and will not expect a new command. For example:
在NSIS脚本中,每一行都被视为一个命令。如果你的命令太长,一行不能用,你可以在行尾使用反斜杠
\
。编译器将把新行看作是对前一行的补充,而不会期望有新的命令。
Messagebox MB_OK|MB_ICONINFORMATION \
"This is a sample that shows how to use line breaks for larger commands in NSIS scripts"
If you want to use a double-quote in a string you can either use $\"
to escape the quote or quote the string with a different type of quote such as `
or '
.
如果你想在字符串中使用双引号,你可以使用$\"
来转义引号,或者用不同类型的引号来引用字符串,如`
或者'
。
For more details about the script format, see Script File Format.
The default extension for a script file is .nsi
. Header files have the .nsh
extension. Header files can help you arrange your script by dividing it to more than one block of code, you can also put functions or macros in header files and include the header files in multiple installers. This makes updating easier and it also makes your scripts easier to read. To include a header file in your script use !include
. Header files that reside in the Include directory under your NSIS directory can be included just by their name. For example:
脚本文件的默认扩展名是.nsi
。头文件的扩展名为.nsh
。头文件可以通过将脚本划分为多个代码块来帮助您安排脚本,您也可以将函数或宏放在头文件中,并将头文件包含在多个安装程序中。这使得更新更容易,也使您的脚本更易于阅读。要在脚本中包含头文件,请使用!include
。驻留在NSIS目录下的Include目录中的头文件可以仅通过它们的名称来包含。
!include Sections.nsh
2.3 Scripting structure
A NSIS script contains Installer Attributes, Pages and Sections/Functions. You can also use Compiler Commands for compile-time operations. The OutFile instruction is required and tells NSIS where to write the installer, you also need at least one section.
2.3.1 Installer Attributes
Installer Attributes determine the behavior and the look and feel of your installer. With these attributes you can change texts that will be shown during the installation, the number of installation types etc. Most of these commands can only be set and are not changeable during runtime.
安装程序属性决定您的安装程序的行为和外观。有了这些属性,你可以改变文本,将显示在安装期间,安装类型的数量等。这些命令中的大多数只能在运行时设置且不可更改。
Other basic instructions are Name
and InstallDir
.
比较基本的指令是Name
和InstallDir
。
For more information about installer attributes, have a look at Installer Attributes.
2.3.2 Pages
A non-silent installer has a set of wizard pages to let the user configure the installer. You can set which pages to display using the Page command (or PageEx for more advanced settings). A typical set of pages looks like this:
Page license
Page components
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles
For the installer, this typical set of pages will display a license agreement, allow selection of components to install, allow selection of an installation directory, and finally install the selected components in the instfiles page. For the uninstaller, it will display a confirmation page, and uninstall in the instfiles page.
2.3.3 Sections
It's common for installers to have several things the user can install. For example in the NSIS distribution installer you can choose to install additional tools, plug-ins, examples and more. Each of these components has its own piece of code. If the user selects to install this component then the installer will execute that code. In the script, that code is defined in sections. Each section corresponds to one component on the components page. The section's name is the displayed component name and the section code will be executed if that component is selected. It is possible to build your installer with only one section but if you want to use the components page and let the user choose what to install, you'll have to use more than one section.
每个组件都有自己的一段代码。如果用户选择安装该组件,则安装程序将执行该代码。在脚本中,该代码是在条款中定义的。每个条款对应于组件页面上的一个组件。条款的名称是显示的组件名称,如果该组件被选中,条款代码将被执行。您可以只使用一个条款构建安装程序,但如果您想使用组件页面并让用户选择安装什么,则必须使用多个条款。
Uninstallers can also have multiple sections. Uninstaller section names are prefixed with 'un.'. For example:
卸载程序也可以有多个部分。卸载程序部分名称以“un.”作为前缀。
Section "Installer Section"
SectionEnd
Section "un.Uninstaller Section"
SectionEnd
The instructions that can be used in sections are very different from the installer attributes instructions, they are executed at runtime on the user's computer. Those instructions can extract files, read from and write to the registry, INI files or normal files, create directories, create shortcuts and a lot more. You can find out more in Instructions.
可以在条款中使用的指令与安装程序属性指令有很大的不同,它们在运行时在用户的计算机上执行。这些指令可以提取文件、读写注册表、INI文件或普通文件、创建目录、创建快捷方式等等。
The most basic instructions are SetOutPath
which tells the installer where to extract files and File
which extracts files.
最基本的指令是SetOutPath
,它告诉安装程序在哪里提取文件,File
则提取文件。
Example:
Section "My Program"
SetOutPath $INSTDIR
File "My Program.exe"
File "Readme.txt"
SectionEnd
For more information about sections see Sections.
2.3.4 Functions
Functions can contain script code, just like sections. The difference between sections and functions is the way they are called. There are two types of functions, user functions and callback functions.
函数可以包含脚本代码,就像条款一样。条款和函数之间的区别在于调用它们的方式。有两种类型的函数,用户函数和回调函数。
User functions are called by the user from within sections or other functions using the Call
instruction. User functions will not execute unless you call them. After the code in the function has executed the installer will continue executing the instructions that came after the Call
instruction, unless you have aborted the installation inside the function. User functions are very useful if you have a set of instructions that need to be executed at several locations in the installers. If you put the code into a function you can save the copying time and you can maintain the code more easily.
用户使用Call
指令从条款或其他函数中调用用户函数。用户函数除非调用它们,否则不会执行。在函数中的代码执行之后,安装程序将继续执行Call
指令之后的指令,除非您中止了函数内部的安装。如果您有一组指令需要在安装程序中的多个位置执行,那么用户函数非常有用。如果将代码放入一个函数中,可以节省复制时间,并且可以更容易地维护代码。
Callback functions are called by the installer upon certain defined events such as when the installer starts. Callbacks are optional. If for example you want to welcome the user to your installer you can define a function called .onInit
. The NSIS compiler will recognize this function as a callback function by the name and will call it when the installer starts.
安装程序在某些已定义的事件(如安装程序启动时)上调用回调函数。回调函数是可选的。例如,如果你想欢迎用户使用你的安装程序,你可以定义一个名为.oninit
的函数。NSIS编译器会根据名称将这个函数识别为回调函数,并在安装程序启动时调用它。
Function .onInit
MessageBox MB_YESNO "This will install My Program. Do you wish to continue?" IDYES gogogo
Abort
gogogo:
FunctionEnd
Abort
has a special meaning in callback functions. Each callback function has its own meaning for it, have a look at Callback
Functions for more information. In the above example Abort
tells the installer to stop initializing the installer and quit immediately.
For more information about functions see Functions.
2.3.5 Working with Scripts
2.3.5.1 Logical Code Structures
Conditionally executing code, or executing code in a loop can be done using StrCmp
, IntCmp
, IfErrors
, Goto
and more. However, there's a much easier way do this. The LogicLib
provides some very simple macros that allow easy construction of complex logical structures. Its syntax, explained in LogicLib.nsh
, is similar to other programming languages and can prove to be simpler for beginners and advanced users alike.
有条件地执行代码或在循环中执行代码可以使用StrCmp
、IntCmp
、IfErrors
、Goto
等。但是,有一种更简单的方法。LogicLib
提供了一些非常简单的宏,这些宏允许简单地构造复杂的逻辑结构。
For example, checking a value of a variable without the LogicLib
can be done as follows.
StrCmp $0 'some value' 0 +3
MessageBox MB_OK '$$0 is some value'
Goto done
StrCmp $0 'some other value' 0 +3
MessageBox MB_OK '$$0 is some other value'
Goto done
# else
MessageBox MB_OK '$$0 is "$0"'
done:
However, with the LogicLib
the code is much more readable and easy to understand, as can be seen in the following example.
${If} $0 == 'some value'
MessageBox MB_OK '$$0 is some value'
${ElseIf} $0 == 'some other value'
MessageBox MB_OK '$$0 is some other value'
${Else}
MessageBox MB_OK '$$0 is "$0"'
${EndIf}
The same can also be done using a switch, as shown in the following example.
${Switch} $0
${Case} 'some value'
MessageBox MB_OK '$$0 is some value'
${Break}
${Case} 'some other value'
MessageBox MB_OK '$$0 is some other value'
${Break}
${Default}
MessageBox MB_OK '$$0 is "$0"'
${Break}
${EndSwitch}
Multiple conditions are also supported. The following example will notify the user, if both $0
and $1
are empty.
${If} $0 == ''
${AndIf} $1 == ''
MessageBox MB_OK|MB_ICONSTOP 'both are empty!'
${EndIf}
The LogicLib
removes the need for labels and relative jumps, thus prevents label name conflicts, and removes the need to manually adjust relative jump offsets every time the script is changed.
It also simplifies looping by supporting the common while
, do
and for
loops. All of the following examples count to five using the 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
To use the LogicLib
the following line needs to be added near the top of the script.
要使用LogicLib
,需要在脚本顶部附近添加以下行。
!include LogicLib.nsh
More examples can be found in LogicLib.nsi
.
2.3.5.2 Variables
You can declare your own variables ($VARNAME
) with the Var
command. Variables are global and can be used in any Section or Function.
变量是全局的,可以在任何Section或Function中使用。
Declaring and using a user variable:
Var BLA ;Declare the variable
Section bla
StrCpy $BLA "123" ;Now you can use the variable $BLA
SectionEnd
In addition there is a stack, which can also be used for temporary storage. To access the stack use the commands Push
and Pop
. Push
adds a value to the stack, Pop
removes one and sets the variable.
此外还有一个堆栈,它也可以用于临时存储。使用Push
和Pop
命令访问堆栈。Push
向堆栈添加一个值,Pop
移除一个值并设置变量。
For shared code, there are 20 registers available (like $0
and $R0
). These static variables don't have to be declared and you won't get any name conflicts. If you want to use these variables in shared code, store the original values on the stack and restore the original values afterwards.
对于共享代码,有20个可用寄存器。这些静态变量不需要声明,也不会出现任何名称冲突。如果您想在共享代码中使用这些变量,请将原始值存储在堆栈上,然后恢复原始值。
After calling the function, the variables contain the same value as before. Note the order when using multiple variables (last-in first-out):
Function bla
Push $R0
Push $R1
...code...
Pop $R1
Pop $R0
FunctionEnd
2.3.5.3 Debugging Scripts
The more you work with NSIS the more complex the scripts will become. This will increase the potential of mistakes, especially when dealing with lots of variables. There are a few possibilities to help you debugging the code. To display the contents of variables you should use MessageBoxes
or DetailPrint
. To get a brief overview about all variables you should use the plug-in DumpState
. By default all actions of the Installer are printed out in the Log Window. You can access the log if you right-click in the Log Window and select "Copy Details To Clipboard". There is also a way to write it directly to a file, see here.
使用NSIS越多,脚本就会变得越复杂。这将增加出错的可能性,尤其是在处理大量变量时。有几种可能的方法可以帮助您调试代码。要显示变量的内容,您应该使用MessageBoxes
或DetailPrint
。要获得关于所有变量的简要概述,您应该使用插件DumpState
。默认情况下,安装程序的所有操作都打印在日志窗口中。您可以访问日志,如果您在日志窗口中右键单击并选择“复制详细信息到剪贴板”。
2.3.6 Script Execution
When a user runs an installer or uninstaller, pages are displayed in the order they were defined in the script. When the instfiles page is reached, sections, corresponding to the selected components, are executed in the order they were defined in the script. If the components page is not displayed, all sections are executed, assuming they were not unselected or somehow disabled by the script.
当用户运行安装程序或卸载程序时,页面将按照它们在脚本中定义的顺序显示。当到达instfiles页面时,对应于所选组件的条款将按照脚本中定义的顺序执行。如果没有显示组件页面,则执行所有部分,假设脚本没有取消选择或禁用它们。
Beside code in sections, there's also code in callback functions. If defined, they might be executed before the sections code. For example, the .onInit
callback function is executed before anything else in the script. There are also page callback functions which are executed at certain points of the page display process.
除了条款中的代码,还有回调函数中的代码。如果定义了,它们可以在片段代码之前执行。例如,.onInit
回调函数在脚本中任何其他东西之前执行。还有一些页面回调函数在页面显示过程的某些点上执行。
2.3.7 Compiler Commands
Compiler commands will be executed at compile time on your computer. They can be used for conditional compilation, to include header files, to execute applications, to change the working directory and more. The most common usage is defines. Defines are compile time constants. You can define your product's version number and use it in your script. For example:
编译器命令将在编译时在您的计算机上执行。它们可以用于条件编译、包含头文件、执行应用程序、更改工作目录等等。最常见的用法是定义。定义是编译时常量。您可以定义产品的版本号并在脚本中使用它。
!define VERSION "1.0.3"
Name "My Program ${VERSION}"
OutFile "My Program Installer - ${VERSION}.exe"
For more information about defines see Conditional Compilation.
Another common use is macros. Macros are used to insert code at compile time, depending on defines and using the values of the defines. The macro's commands are inserted at compile time. This allows you to write a general code only once and use it a lot of times but with a few changes. For example:
另一个常见的用途是宏。宏用于在编译时插入代码,这取决于定义和使用定义的值。宏的命令是在编译时插入的。这允许您只编写一次通用代码,并使用它很多次,但有一些更改。
!macro MyFunc UN
Function ${UN}MyFunc
Call ${UN}DoRegStuff
ReadRegStr $0 HKLM Software\MyProgram key
DetailPrint $0
FunctionEnd
!macroend
!insertmacro MyFunc ""
!insertmacro MyFunc "un."
This macro helps you avoid writing the same code for both the installer and the uninstaller. The two !insertmacros
insert two functions, one for the installer called MyFunc
and one for the uninstaller called un.MyFunc
and both do exactly the same thing.
这个宏可以帮助您避免为安装程序和卸载程序编写相同的代码。两个!insertmacros
插入两个函数,一个用于安装程序名为MyFunc
,另一个用于卸载程序名为un.MyFunc
,两者都做相同的事情。
For more information see Compile Time Commands.
2.4 Compiler
The second thing you need to do in order to create your installer after you have created your script is to compile your script. MakeNSIS.exe
is the NSIS compiler. It reads your script, parses it and creates an installer for you.
To compile you can right-click your .nsi
file and select Compile NSIS Script. This will cause MakeNSISW
, the NSIS Compiler Interface, to launch and call MakeNSIS
to compile your script. MakeNSISW
receives the output of MakeNSIS
and presents it to you in a window where you can see it, copy it, test the installer and more. Using makensis.exe
from the command prompt is also possible.
The compiler will check your script and give you warnings or an error. If an error occurs (i.e. 2 parameters required but only 1 given) the compiler will abort and a short error message including the line number will be displayed. For non-critical errors the compiler will give a warning (i.e. two DirText
commands in one script). If your script has no errors the compiler will output an installer for you to distribute.
NSIS supports different compression methods, as explained here. ZLIB is the default compression method, which is fast and uses only a little bit of memory. LZMA is a good method for the creation of small installers for internet distribution. BZIP2 usually compresses better than ZLIB but not as good as LZMA, it is useful if you need lower memory usage or fast script compilation.
NSIS支持不同的压缩方法,如下所述。ZLIB是默认的压缩方法,它速度快而且只占用很少的内存。LZMA是为internet分发创建小型安装程序的好方法。BZIP2的压缩性能通常比ZLIB好,但不如LZMA好,如果您需要更低的内存使用或快速的脚本编译,BZIP2很有用。
It is also possible to compile Windows installers on Linux, BSD or Mac OS X servers. See Building NSIS for details.
2.5 Modern UI
A popular user interface for NSIS is the Modern User Interface. It has an interface like the wizards of recent Windows versions. The Modern UI is not only a customized resource file, it has a lots of new interface elements. It features a white header to describe the current step, a description area on the component page, a welcome page, a finish page that allows the user to run the application or reboot the system and more.
For more information, see the Modern UI 2 Readme and the Modern UI Examples.
2.6 Plug-ins
NSIS support plug-ins that can be called from the script. Plug-ins are DLL files written in C, C++, Delphi or another programming language and therefore provide a more powerful code base to NSIS.
A plug-in call looks like this:
DLLName::FunctionName "parameter number 1" "parameter number 2" "parameter number 3"
Every plug-in's function has its own requirements when it comes to parameters, some will require none, some will accept as many parameters as you want to send. Examples:
nsExec::ExecToLog '"${NSISDIR}\makensis.exe" /CMDHELP'
Pop $0 ; Process exit code or "error"
InstallOptions::dialog "$PLUGINSDIR\test.ini"
Pop $0 ; success/back/cancel/error
NSISdl::download http://download.nullsoft.com/winamp/client/winamp291_lite.exe $R0
Pop $0 ; "success" or a error code
The plug-ins that NSIS knows of are listed at the top of the compiler output (verbose level 4). NSIS searches for plug-ins in the Plugins folder under your NSIS directory and lists all of their available functions. You can use !addplugindir
to tell NSIS to search in other directories too.
NSIS知道的插件列在编译器输出的顶部。NSIS在NSIS目录下的Plugins文件夹中搜索插件,并列出它们所有可用的函数。你可以用!addplugindir
告诉NSIS搜索其他目录。
The NSIS distribution already includes many plug-ins. InstallOptions
is a popular plug-in that allows you to create custom pages, in combination with the NSIS Page commands (See Pages). The Startmenu
plug-in provides a page that allows the user to choose a Start Menu folder. There are a lot of plug-ins for different purposes, take a look in the Docs folder for help files and examples. You can find additional plug-ins online: NSIS Wiki.
You can also create a plug-in yourself. C/C++ and Delphi header files are already available, see the example plugin for how to do this. Source code of included plug-ins can also be found in the source code package.
2.7 More
This tutorial has described the basic NSIS features, to learn more about everything NSIS can do, take some time to read the rest of this manual.