You are on page 1of 14

Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

Articles Development Lifecycle Installation General

Creating an Installer
Hamed Mosavi, 7 Mar 2008

Using NSIS to create a simple installer

Download demo installer - 64.44 KB


Download source script- 1.08 KB

Introduction
There are many tools to create an Installer for our applications. I used two of them. The second one was NSIS and since I
learned it, I did not go further. This article introduces NSIS and shows how to create a simple setup application using

1 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

powerful, yet easy, NSIS scripts.

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.

Table of Contents
Ingredients
The Big Picture
Compiling a Script
Scripts in Detail

Attributes
Variables
Sections
Functions
Pages

Useful Instructions
Acknowledgement

Ingredients
Before starting NSIS, we first need to get its compiler. Beside the NSIS compiler comes a lot of handy tools and plug-ins,
mostly written by the NSIS community. I put a link to those I used in this article here:

Download NSIS setup


Download HM NISEdit

The Big Picture


To create a simple installer with NSIS, we should start learning the NSIS scripting language. The idea is that we create a
single (or multiple) file(s) that contain(s) the script instructions. Then we ask the NSIS compiler to compile the file and
create a setup executable file.

Compiling a Script
After downloading and installing NSIS using the link provided above, all we need to do is create a new text file called
WhatEverName.nsi, type down our commands, right click on the file and select "Compile NSIS Script."

2 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

It's not quite 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 the NSIS Developer Center, you can download other IDEs or integrations to current Editors
like Eclipse. Here's a link to the available text editors page. In the 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 the NSIS Script CHM help file.

After running the IDE, you can either type in commands or use the wizard to create a template for a simple installer.
Personally, I didn't learn to use NSIS scripts until I started creating my own instructions from scratch.

Scripts in Detail
We got NSIS, an IDE and we know we shall write some instructions to create an installer. But what can we type in? In
NSIS, each line is considered a new instruction. The instruction will be known by its name. If we look at the instructions of
a sample NSIS script file, we will see some of these parts: Pages, Sections, Functions, variables and other compiler
commands or attributes. Depending to their names, each of these instructions has special meanings to the compiler.
Below is a sample script that has three of the so-called instructions.

3 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

Understanding pages and sections is quite easy, since they represent the visual equivalent in the final compiled installer.
The above script, if compiled, will produce the following installer:

4 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

The above example section was created in a way that is hidden. We also did not have any functions. Later on, we will
examine them in more detail.

Attributes
Attributes are instructions that define the behavior of the installer, its look and feel or define the behavior of the
commands that will come after them. For example, the Name attribute defines the name of the installer that will be
shown at the title bar of the installer window.

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

5 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

Specifies the output file that MakeNSIS should write the installer to; name of the
OutFile
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 to create a new NSI script file, type the following lines into it:

!include "LogicLib.nsh"
!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'

In NSIS script, we can add macros (lines started with !define) and also we can use scripts
in other files, using the !include compile-time command.

*.nsh files contain 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 a *.nsh
extension.

Please note that when using macros, we need to use both the $ sign and {} while in
variables it is just the $ sign.

Variables

6 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

They hold values for us, just like what we have in our programming languages. To define a variable, we need to use the
var command. To use it, we must use a $ before the variable name:

var varName

...

StrCpy $varName "example value"

Notes when using variables:

All variables are global, so when defining inside functions, we must explicitly use the /GLOBAL switch: Var
/GLOBAL varName
Allowed characters for variable names are: [a-z], [A-Z], [0-9] and _
By default, variables are limited to 1024 characters

Predefined variables:

There are some variables that are already defined in NSIS and we can use them without declaration. Also, we
must be careful and prevent 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 is already set by you when using the InstallDir attribute,
but at runtime the user is able to change it. You can also modify this variable using the StrCpy command.
$OUTDIR: the current output directory. SetOutPath or StrCpy could be used to set this variable.
For more information about variables, refer to the variables section of the NSIS help file.

Constants
Here's a good place to name some of the useful constants that NSIS defines for us. They also added these to their
variable part of the help. Remember the InstallDir attribute? If you don't, it is the attribute that sets the installation
directory for us. Unless you are sure about where exactly you want your installer files to be copied (like C:\MyFolder),
you'll need to know some paths like the Windows folder path or the 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 the $PROGRAMFILES constant in front of the InstallDir attribute, which expected a string.
$PROGRAMFILES will be replaced by the exact path string on the user's 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, On Windows X64, the first one points to C:\Program Files (x86) while the second
$PROGRAMFILES64 points to C:\Program Files.

The Windows desktop directory (usually C:\Windows\Desktop, but detected at


$DESKTOP
runtime).

$EXEDIR The directory containing the installer executable.

$EXEPATH The full path of the installer executable.

7 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

A symbol that contains the path where NSIS is installed. Useful if you want to call
${NSISDIR}
resources that are in NSIS directory, e.g. Icons, UIs.

$WINDIR The Windows directory.

$SYSDIR The Windows system directory.

$TEMP The system temporary directory.

The Start menu folder (useful in adding start menu items using
$STARTMENU
CreateShortCut).
The start menu programs / startup folder. The context of this constant (All Users or
$SMSTARTUP Current user) depends on the SetShellVarContext setting. The default is the
current user.

The documents directory. The context of this constant (All Users or Current user)
$DOCUMENTS
depends on the SetShellVarContext setting. The default is the current user.

The application data directory. The context of this constant (All Users or Current
$APPDATA user) depends on the SetShellVarContext setting. The default is the current
user.

A directory where files awaiting to be burned to CD are stored; this constant is


$CDBURN_AREA
available on Windows XP and above.

For a complete list of constants or requirements for them, please refer to the variables section of the NSIS help.

Sections
"Each NSIS installer contains one or more sections." That means that we need to have at least one section in our script.
But what is the use of a section? You have certainly seen dozens of installers that let you choose what to install, like the
very well-known Microsoft Office that lets you chose to install, say, Powerpoint or not.

In NSIS, these options can be given to a user with the help of sections. In our example, Microsoft Powerpoint should
have a particular section and that section indeed has other sections for each feature you select to be installed. It's logical
to have at least one section, since we have at least one feature to install. Don't we? Sections can be hidden, so the user
will not see any feature to select one of them, which most probably will be used in installers with only one section.

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
and you can put it MySec if you want. We are free to put any amount of instruction we like inside a section block. I'm not
going to describe sections in detail here; it makes this article too lengthy. However, there's a lot that you can find on
sections, like how to disable a section, or re-enable it, how to create section groups, how to show section names in bold,
make it optional or forced, etc.

Lab #2

Reload previous file into your editor and add the following:

Section "Dummy Section" SecDummy

8 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

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

The above code creates two sections. We want the first one to be visible. The second section
above will be called when uninstalling. The 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.

WARNING: please note that calling RMDir to remove our application folder is really
DANGEROUS. The reason is quite simple. Think about a beginner user that changes the
default folder path to C:\Program Files. You save the path when installing and, upon calling
RMDir, the installer tries removing the whole Program Files folder.

Functions
"Functions are similar to Sections in that they contain zero or more instructions." There are two types of functions: user
functions and callback functions. User functions will be called manually by using the 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

9 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

The above code shows how to write .onInit so that, as soon as the installer starts, a message box asks the user if
he/she would like to continue. The following table lists some of the common callback functions.

Callback function name When it's called

Will be called when the installer is nearly finished initializing. If the .onInit function
.onInit
calls Abort, the installer will quit instantly.

Is called when the user hits the Cancel button, and the install hasn't already failed. If
.onUserAbort
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.

Is called whenever the mouse position over the sections tree has changed. This allows
.onMouseOverSection you to set a description for each section, for example. The section ID on which the
mouse is currently over is stored temporarily in $0.

Will be called when the uninstaller is nearly finished initializing. If the un.onInit
un.onInit
function calls Abort, the uninstaller will quit instantly.

For more information on functions, refer to the function section in NSIS help.

Lab #3

Let's add two functions to our installer: a callback one and a user one.

Function .OnInit

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

Here we create a callback function .onInit that will be called whenever the installer starts
up before the pages being shown. Then we copy a message into the $0 variable that has
already been defined for us by the compiler. Finally, we push it so that we can use it in a
function later on and we call a function.

The user function tries to pop a string off the stack and into $R0 that again has already
been defined by the compiler. We check to make sure it has a value. If it does 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 stacks), use variables

10 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

and how easy it is to use logiclib, which we already included. If we were not to use
logiclib, we would have to write a code similar to IBM x86 assembly instead of that of
$IF.

Pages
"Each (non-silent) NSIS installer has a set of pages. Each page can be an NSIS built-in page or a custom page." At the
time I wrote this article, there was a new version of NSIS available that gave better support for custom pages, but I was
too lazy to read them. I leave that to the enthusiastic reader. The page instruction is simple:

Page license

The above code shows a simple empty license page. To force it to show your license file, you should use the 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 the UI is to use a modern UI. It's not only simpler, but also much more familiar and
nicer. Modern UI is included in NSIS after version 2.0. Documentation to the UI is available here. As I'm writing this
article, the second version of the 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. The 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 is showed. It is, for example, useful when we want to ignore the
next page or 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 a license page. The function checks a variable to see if the application
already exists. If it exists, the license page will be ignored and the next page will be shown.

Lab #4

If we run our installer right now, it will work! It uses sections, our attributes and also some
default behavior to do required operations. The problem is that there is not any
customization available to the user. Let's get user some choices using pages of the modern
UI.

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "License.txt"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY

11 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

!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

Just add some pages and we're done. Before we finish this lab, please note how we used
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 the section index and it is used to access a section.

The last 8 lines are there just to show "A Section" text when the mouse is over the "Dummy
Section."

Useful Instructions
The following table lists some of the instructions that you will probably need.

Instruction What it does Usage

Adds file(s) to be extracted


File to the current output path File "Bin\7z\*.*"
($OUTDIR)

Causes the installer to exit


Quit
as soon as possible

Executes the specified


ExecWait program and wait for the ExecWait 'c:\SomeProgram.exe' $0
executed process to quit

Adds the string "message"


DetailPrint to the details view of the DetailPrint "message"
installer

Sets the user variable $x


Strlen Strlen $0 ${SETUP_NAME}
with the length of str

Reads from the registry into


ReadRegStr ReadRegStr $0 HKLM Software\NSIS ""
the user variable

Copies files from the source


CopyFiles to the destination on the CopyFiles "$0\cid.dll" "$INSTDIR"
installing system

12 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

Creates (recursively if
CreateDirectory necessary) the specified CreateDirectory "7z"
directory

Creates a shortcut
link.lnk that links to CreateShortCut
CreateShortCut target.file, with "$SMPROGRAMS\$STMenuDirectory\Help.lnk"
optional parameters "$INSTDIR\Yas.chm"
parameters
IfFileExists
Checks for the existence of
IfFileExists "$INSTDIR\${SQL_DATABASE_NAME}.mdf" 0
file(s)
Goon_label
Deletes file (which can be a
file or wildcard, but should Delete
Delete
be specified with a full path) '"$INSTDIR\${SQL_DATABASE_NAME}.mdf"'
from the target system

DeleteRegKey Deletes a registry key DeleteRegKey[/ifempty] root_key subkey


Deletes a registry value;
valid values for root_key
DeleteRegValue DeleteRegValue root_key subkey key_name
are listed under
WriteRegStr

Final Note

Please note that the installer included in this article will create a folder in your Program Files named CPLab. Inside the
folder, you have an Uninstall.exe that will clean up everything for you. There are still plenty features or needed tips to
mention here, but if I do that, then I'm putting the NSIS help in another order here. I think this is enough to start creating
your installers and, as I did when creating my own, you'll be sure find what you need quickly. Good luck!

Acknowledgement and Disclaimer


Most of the text and codes here have been extracted from NSIS help and samples. I tried to put quotes around texts, but
for codes, it would rather make it dirty. Thanks to the NSIS community, there are plenty of codes available to download
here.

History
2008/03/04 : Tutorial created

License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

13 of 14 10/4/2017, 11:06 AM
Creating an Installer - CodeProject https://www.codeproject.com/Articles/24187/Creating-an-Installer?displ...

About the Author


Hamed Mosavi
Software Developer (Senior)
Iran (Islamic Republic of)

No Biography provided

You may also be interested in...


Designing For DevOps A Solution Blueprint for
DevOps

A quick introduction: SAPrefs - Netscape-like


Create an MSI installer with Preferences Dialog
WiX

Easy Installer Generate and add keyword


variations using AdWords
API

Comments and Discussions


27 messages have been posted for this article Visit https://www.codeproject.com/Articles/24187/Creating-an-
Installer to post and view comments on this article, or click here to get a print view with messages.

Permalink | Advertise | Privacy | Terms of Use | Mobile Article Copyright 2008 by Hamed Mosavi
Select Language
Web01 | 2.8.170927.1 | Last Updated 7 Mar 2008 Everything else Copyright CodeProject, 1999-2017

14 of 14 10/4/2017, 11:06 AM