Home |
Last modified: 16-06-2020 |
Nullsoft Scriptable Install System (NSIS) is an alternative, equally open-source, to InnoSetup to build packages (I haven't checked Inno's Pascal scripting language, so can't tell how it fares against NSIS.) Unlike VB's Packaging and Deployment Wizard (PDW), NSIS generates a single EXE.
The NSIS install program added items in the context menu that pops up when you right-click in Windows Exploder. Create an NSIS script, right-click on it, and choose "Compile NSIS Script". This will launch the MAKENSISW.EXE front-end, display compiling messages, and whether it succeeded or failed. Once the compiling is done, you'll have an EXE installer in the output directory you specified in the NSI script.
The default extension for a script file is .nsi. Header files have the .nsh extension. 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.
A NSIS script can contain Installer Attributes and Sections/Functions. You can also use Compiler Commands for compile-time operations. Required is the OutFile instruction, which tells NSIS where to write the installer, and one section. 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).
In a common installer there are several things the user can install. For example in the NSIS distribution installer you can choose to install the source code, additional 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 in sections. Use of multiple Sections only make sense if you also include Pages since Sections show up as options that the user can choose to install.
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 will not execute unless you call them. Callback functions are called by the installer upon certain defined events such as when the installer starts.
You can declare your own variables ($VARNAME) with the Var command. Variables are global, case-sensitive, and can be used in any Section or Function. Note that constants, ie. data declared using a !define line are accessed through ${CONST} instead of $CONST, and constants are not case-sensitive. An alternative to using your own variables is to use global variables declared by NSIS, namely $0 through $9, and $R0 through $R9.
Compiler commands will be executed on 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:
Another common use is macros. Macros are used to insert code on compile time, depending on defines and using the values of the defines.
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 have to right-click your .nsi file and select Compile NSI or Compile NSIS (with bz2)
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"
The plug-ins that NSIS knows of are listed at the top of the output of the compiler. 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.
To add comments, you can use the prefix ; or #, or C's /*... */ .
There are several tools that generate a working NSIS script using wizards and templates. A great way to get started, and allow users who don't know NSIS to build basic installers without learning much about NSIS.
http://nsis.sourceforge.net/System.html
The System plug-in lets you call functions in DLL's, whether this DLL is a regular C file, or a COM DLL. The System first looks for the DLL you're calling in the current directory. There seems to be two syntaxes available. Here's the old syntax:
... and here's the new syntax:
In other words, the new syntax combines declaration and definition, while the old syntax keeps the two separate.
Here's an example:
This function takes two parameters, a string and a pointer to an integer which will return the number of characters written into the string, and an integer as its return type. Since the string is only used for writing, you must prepend its name with a dot (.r0); Since the second parameter is used for both input and output, you must give it twice (r1r1); Finally, since, by definition, return variables are only used as output, remember to always prepend a dot (.r2).
Another one, using the void notation:
Here's how it works:
Here's how to use the Win32 API GetSystemDirectory() to retrieve the full path to Windows' system directory:
I'm surprised I don't have to first make sure that $0 is set to ${NSIS_MAX_STRLEN} to make sure there's enough room to fill this variable, but it works.
Note: First, it is recommended to turn 'PluginUnload' off before making multiple calls to System.dll. According to Brainsucker (and others), this will speed up execution of the installer package. However, if you call the System plug-in just once, you can remove SetPluginUnload alwaysoff, SetPluginUnload manual and System::Free 0.
System::Free doesn't free resources used by the System plug-in. It frees resources allocated using the System plug-in using System::Alloc or the special System::Call syntax. If you pass $0 to it, it will try to free the memory pointed to by $0 which is a bad idea unless you've saved an address of some allocated memory in it.
If you use System::Free 0 it will simply do nothing. Why this is needed will be clear once you read about SetPluginsUnload.
/NOUNLOAD on System::... plugin calls or SetPluginUnload alwaysoff
Second, you have to change the output directory to that where the DLL you want to use is. It may also work if the DLL is on the system path, but this hasn't been tested.
Some functions make use of structures. I seem to understand that you must append & when you need to use a specific size, eg. &i2 when you want to use a two-byte integer in case the OS uses four-byte integers. Here's how to use them:
Here, we create and fill a structure on the stack, extract its address into $1, read each of its members into variables, and display their contents. Note that the size of the structure is appended to the structure (read into r6, here):
You actually need 16 bytes to be allocated for GUID (128 bit) (I meaning your system::alloc). The alternative way completely thru ole and kernel functions (string guid at $3):
System::Alloc 16
Pop $1
System::Alloc 80
Pop $2
System::Call 'ole32::CoCreateGuid(i r1) i'
System::Call 'ole32::StringFromGUID2(i r1, i r2, i 80) i'
System::Call 'kernel32::WideCharToMultiByte(i 0, i 0, i r2, i 80, t .r3, i ${NSIS_MAX_STRLEN}, i 0, i 0) i'
System::Free $1
System::Free $2
Create a GUID, a Globally Unique Identifier
Create a GUID, a Globally Unique Identifier
IPtr->MemberIdx -> Call member with member index from interface given by interface pointer IPtr (IPtr will be passed to proc automatically, use like C++ call).
1. No need to specify datatype?
System::Call '${sysGetDiskFreeSpaceEx}(r1,.r2,,.)'
2. The documentation doesn't say that we can use $0 in System:
System::Call 'user32::PostMessageA(i,i,i,i) i ($0,${WM_CLOSE},0,0)'
5. What is the "n" datatype?
:OpenSCManagerA(n, n, i
System::Call 'advapi32::CloseServiceHandle(i r5) n'
=> Options section in system.txt? "None -> n (0 (null) for input / specifies no output is required)"
"n - no redefine. Whenever this proc will be used it will never be redefined either by GET or CALL. This options is never inherited to childs."
7. No need to specify return variable?
9. Confused with variable mappings:
10. In Lobo's CHM tutorial, why the trailing R1? Void = any type?
system::Call "kernel32::GetCurrentDirectory(i 255, t .r0) v r1"11. What's the "?e" for?
"Additional regs -> c(Cmdline) d(instDir) o(Outdir) e(Exedir) a(lAng)"
"e - call GetLastError() after procedure end and push result on stack,"
To find out the index of a member in a COM interface, you need to search for the definition of this COM interface in the header files that come with Visual C/C++ or the Platform SDK. Remember the index is zero based.
Here, we'll just display a message box. Just copy/paste this code into dummy.nsi, right-click on this file, and select "Compile NSIS Script":
A section is a bit like a routine, ie. a way to pack instructions. If you give it a name (the section above doesn't have any, so is silently ran), and add a "Page components" + "Page instfiles" instructions, the user is presented with a list of options, and invited to click on Install to actually run each section that was selected in the first page:
io2.chm
Here, we either find a way to check that the user has TCP/IP installed, how to dial out in PPP, and tx/rx files with eg. ftp or wget, OR we find a small and reliable DOS TCP/IP + PPP package, and use this instead.
In the Archive section of the site, two plug-ins are available that can decompress a zipped file:
To use ZipDLL...
Alernatively, if you prefer to use the MUI, it appears that you can use this instead:
"On Success, the string "success" is on top of the stack, else an error message." ?
This minimal script includes a file inside the installer, and extracts it on the host. For this to work, you must have a dummy "myfile.exe" in the directory where this NSIS script lives. Just copy/paste this code in a text file named eg. myinst.nsi, right-click on this file, and choose "Compile NSIS Script":
Here, we check if a file exists on the host; If not, we download it from the web, and run it silently:
There are two basic commands regarding pages, Page and UninstPage. The first adds a page to the installer, the second adds a page to the uninstaller. On top of those two there is the PageEx command which allows you to add a page to either one and with greater amount of options. PageEx allows you to set options to the specific page you are adding instead of using the default that's set outside of PageEx. The page order is set simply by the order Page, UninstPage and PageEx appear in the script.
Each (non-silent) NSIS installer has a set of pages. Each page can be a NSIS built-in page or a custom page created by a user's function (with InstallOptions for example).
Here's how to display a license page, followed by an inputbox to let the user choose a destination directory, followed by the list of sections available, before actually installing stuff:
Here's how to display a custom page:
Here's how to let the user select the familiar "Basic, Full, Custom":
While the Modern UI module available in NSIS 2 offers enhanched support for tree-like lists, you can build this kind of interface with NSIS 1. This example displays a one-level section "MS FlexGrid", followed by a two-level section "VideoSoft" that contains two items "VS Print" and "VS FlexGrid".
It may happen that you want a section to be automatically checked if the user checks another section, such as when selecting an EXE that requires an OCX to work. Note that I didn't handle the case where the user unselects the Application section which should also uncheck the OCX section as well, and also remember to add !include "Sections.nsh" at the top of your script.
Here's a first way to do this :
Here's a second way:
Use GetWindowsVersion in .onInit and accodring to the results disable or enable sections using SectionSetFlags or hide it using SectionSetText.
Here, we'll extract the version number from an OCX to get a string in the form "1.2.3.4", download an INI file from a web server that will give tell us the version number of the file over there, compare the two token by token, each time deciding whether to go on to the next test, exit, or download the version on the web server if it is newer. Since I'm still a NSIS newbie, there's most likely a cleaner way to do this, but here goes, using BigMac2003, StrTok():
Another way to achieve this, using Sunjammer's VersionCheck():
Yet another way, using Deguix's StrTok macro in Include\StrFunc.nsh:
If you are referring to GetDllVersion in my sysinfo DLL it will work on a path because it calls LoadLibrary on the DLL. *However* not all DLLs support the GetDllVersion mechanism. The DLL has to export a method called DllGetVersion - if it doesn't then this method will not return any version information. In that case you have to fall back to one of the other means of querying the DLL for a version number, i.e. GetFileVersion.
I can't be sure if GetFileVersion will search the default paths or not, it's a bit hard to tell from the Win32 API docs. Basically they say that GetModuleHandle which it calls does not need a path, it doesn't say what happens if it doesn't have one.
I *believe* it will search the default path since that whole chunk of the Win32 API is connected with loading and using DLLs which involves obeying path information.
InstType /CUSTOMSTRING=Personnalisée
It appears that the Modern UI options provides a much better solution to build multi-language installers.
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.
Here's how to loop 5 times:
Another way:
Yet another way:
In case you don't need to check for version numbers...
This uses the FindProcDLL::FindProc plug-in (here also):
Other solutions in Uninstall: How to make sure the app isn't running?
Joost Verburg >>You can call any DLL using the System DLL. That quote refers to a direct call without the System plug-in.
Does this refer to NSIS plug-in's written as DLL's and located in NSIS\Plugins\ ?
Justin wrote a PHP script to generate a basic script.
The Local one is for the compiler system, it is actually being converted to two StrCpy commands that set two variables. This way, the EXE that you generate holds a copy of the version number of the DLL. With the value of the Local command (which is the version on your system), you can compare the version on the user's system using the other command. Thanks to GetDLLVersionLocal(), you don't have to save the version number in a file that you will insert in the EXE using the File command.
ie. how to run File with files that have a different extension (so *.x won't work)? Can't do. File only works with constants, not variables. The following doesn't work:
Note that DLLs & OCXs sometimes fail to register automatically at install time because they depend on a newer version of some runtime library (msvcrt.dll and msvcp60.dll being common culprits). These can't yet be upgraded because it's being used by the installer itself, so registration will fail and if it's not storing the result to DllRegisterServer (or just shelling to regsvr32 /s) you won't notice until you launch the app.
What does this do?
Escape it with $\"
By Neal Olander
NSIS stands for Nullsoft Scriptable Install System. It is a free software package that you, as a developer, can use to package your software application for delivery to users. Almost every software package is installed using an installer like NSIS or InstallShield or Wise. Most installers are commercial products that you have to pay for, but NSIS is free.
There are three main sources of information about NSIS: (1) the NSIS web site at nsis.sourceforge.net; (2) the NSIS discussion forum at forums.winamp.com/forumdisplay.php?s=&forumid=65; and (3) the on-line help within the NSIS product, which will be on your computer after you download NSIS from the NSIS web site.
Go to the NSIS web site at nsis.sourceforge.net and follow the instructions.
NSIS allows you (a developer) to package files for delivery to users. The files are packaged into a single file, called an "installer" file. The installer file is an executable, normally called setup.exe. You can deliver this installer file either on a CD or users can download the installer over the web. The files may include software applications, DLLs, help files, data files, or any kind of file you want. NSIS helps the user put the files onto their computer, and makes sure the files get put into the right places. It also can setup registry entries, desktop shortcuts, and Start menu buttons. NSIS will pop-up windows for the user to read and follow. You do not have to deal with the hassle of creating the windows: NSIS does all the hard work for you. Your biggest job is identifying the files that are to be delivered.
The steps are
NSIS follows the instructions that you put into your script file. NSIS will do a lot automatically (such as pop-up windows, check for disk space, create necessary folders) but you have to tell it what files to install, and where to install them.
The NSIS script file is a text file that you create in a text editor. It contains instructions about what files to install. You can create the script file in several ways: (1) you can type it by hand in any plain-text editor; (2) You can modify a sample NSIS script file from the NSIS web site or the NSIS dowload files; or (3) You can download and run the HM NIS Edit program which includes a wizard to create scripts.
The script file is a text file that you write. After you write it, you run it through the NSIS compiler and the compiler will tell you if there are any errors. If there are no errors, the NSIS compiler will output the installer executable, normally named setup.exe. The installer file contains all the installation instructions, plus the files you are delivering. The installer file is binary and you cannot read it in a text editor.
The files you are delivering are embedded inside the installer executable. The compiler, when compiling, reads the files from your computer's disks and compresses the files and puts them inside the installer exectuable. That way, the user only has to fetch a single file, the installer executable, and run it.
After the user gets the installer executable from you (either from a CD, or downloaded from the web) the user just runs the installer (usually called setup.exe). The installer will pop-up some windows asking the user to read a license agreement, and to select a folder for the files to be put into. The installer will then extract your files from within its own file, decompress them, and put them into folders on the users computer.
By default, the files go into a folder that the user selects in the pop-up windows. But you can force files to go into any folder you want. If the folders do not exist, you can create them in the script.
The syntax of the NSIS script files is simple but a little bit primitive. For details, visit the on-line help in the NSIS web site. The key thing to remember is that everything you need to do in your installation has been done before, so there is _some_ way to get it done. Ask questions on the NSIS forum and you will get detailed instructions on how to achieve your goals. NSIS is pretty powerful, and will do a lot of things automatically, so the script files tend to be rather small.
You don't need to memorize all the overhead stuff from a NSIS file ... most developers just copy existing scripts and modify the "middle" where the list of files is contained. Go to the online documenation and start reading sample scripts.
The most important command in the script is the File command. This command looks like:
The file command tells the NSIS compiler to fetch the named file (whizbang.exe) from your disk (at compile time) and put the file into the compiler's output installer file. The folder here is the folder on your (the developer's) computer, not the users computer. The destination folder on the users computer will be chosen by the user during the installation process, from the GUI, so you do not have to worry about that in your script.
When you are delivering lots of files, NSIS will let you create a folder tree. It is best if you let the user (in the GUI) identify where the tree should start, say C:\Program Files\Any Place. That folder will be identified in the script as $INSTDIR. You can put files in subfolders under $INSTDIR by using the SetOutPath command immediately before the File command, as in:
You can also use the CreateDirectory command to explicitly create specfic folders on the users computer. Generally, you do not want to use hard-coded paths for the destination folders, because it is dangerous to make assumptions about the users drive ID letter (C: or D:, etc) and also the user should control where files go. That is why you should always use $INSTDIR as the starting point for the destination folder.
If your application has lots of pieces, and some pieces are optional, then you use the Section command in your script. The Section command breaks your files into groups, and the NSIS intall GUI will (automatically!) build a list of these pieces and present them to the operator. After the operator selects which pieces he or she wants installed, the NSIS installer will install only those pieces selected. Use of Sections is optional. Your script may use sections like this:
You can create tree-like file groupings using the SectionGroup command, as in:
The MUI is an optional user-interface that can be used with NSIS. It presents the user with "modern" looking windows. You can get sample NSIS scripts that use MUI from the NSIS web site, or you can use the NIS EDit program wizard to generate a script containing MUI constructs. The on-line NSIS documentation includes MUI instructions.
The important MUI commands each pop-up a single window for the user to read or act on. A typical sequence of MUI command (each one pops up a single window) is:
There is no limit to the number of files. But the NSIS installer file is limited to 2 GB. If you need to install more than that, you can either create two separate installer files, or deliver some files "outside" the installer executable.
If you want to deliver files to your users outside the installer file, and you are delivering on a CD or DVD, then you manually copy the "outside" files to the CD, and use the CopyFiles command in your script. This command will copy files from the CD (or DVD) to the users drive. The CopyFiles command looks like:
The $EXEDIR is often used in the CopyFiles command. $EXEDIR is the path that the user is running the installer executable from. When the user is installing from a CD, $EXEDIR might be "E:" or "G:\top_folder" When installing from a CD (or DVD) you can use $EXEDIR as a starting point and then use relative paths from it to identify the location of the "outside" files on the CD.
By default, a normal NSIS script will prompt the user to browse and identify a single destination folder, which is refered to as $INSTDIR in your script. But if you need to prompt the operator to identify multiple destinations then you use the following MUI logic. Put this logic _after_ the first MUI_PAGE_DIRECTORY line (which is the first GUI prompt for a folder):
In the example above, this will pop-up a second window asking the user to browse and identify a folder. The folder selected by the user will be stored in $ALTERNATIVE_FOLDER (in the example above) and your script can then ouput files there such as:
You'll find information on how to build NSIS scripts at the following places:
Good stuff: