Categories
Coding

Using the NSIS Install Engine

Whilst packaging up a plugin based on the Skype API that I had been writing, I was looking for a way to bundle it all up cleanly. The finished plugin consisted of an .exe, a COM wrapper DLL (the very useful Skype4COM wrapper), and some HTML documentation for the C++ code (generated by doxygen). I thought this might be a good opportunity to have a look at NSIS, the installer generator that is used by a huge number of open-source (and other) projects.

My install requirements were quite simple. The following steps needed to be performed:

  • Copy the .exe and associated HTML docs to the target system;
  • Copy the COM DLL to the target system;
  • Register the COM server (by invoking regsvr32);
  • Create any necessary Start Menu items (and an uninstaller);
  • Open a web browser automatically on the index page documentation.

Obviously, the uninstaller would need to remove all files, and also unregister the COM server before uninstalling.

I downloaded NSIS from the web site and fired up the NSIS Compiler. This is a very simple interface that allows you to drag-and-drop .NSI script files into its interface and execute them. The NSIS scripting runtime is a very simple scripting language, with some basic language constructs, and the ability to define and import macros and plugins for extended functionality.
A screenshot of the compiler interface is shown below:

NSIS Compiler Interface

Here is the full installation script for my plugin, annotated with some comments.

; Skype Plugin NSIS Installer Script File
; Rory Winston <rory@researchkitchen.co.uk>
;--------------------------------
;Include some predefined NSIS libraries (for modern UI look and feel)

  !include "MUI.nsh"

;--------------------------------

XPStyle on

;General

  ;Name and file
  Name "Skype Plugin"
  OutFile "SkypePluginInstaller.exe"

  ;Default installation folder
  InstallDir "$PROGRAMFILES\Skype Plugin"

  ;Get installation folder from registry if available
  InstallDirRegKey HKCU "Software\Skype Plugin" ""

;--------------------------------
;Interface Settings

  !define MUI_ABORTWARNING

;--------------------------------
;Pages
; These are predefined "wizard pages" that NSIS can generate for us. Note that I 
; am including a custom license file on the MUI_PAGE_LICENSE page.
  !insertmacro MUI_PAGE_LICENSE "NOTICE.txt"
  !insertmacro MUI_PAGE_COMPONENTS
  !insertmacro MUI_PAGE_DIRECTORY
  !insertmacro MUI_PAGE_INSTFILES

  !insertmacro MUI_UNPAGE_CONFIRM
  !insertmacro MUI_UNPAGE_INSTFILES

;--------------------------------
;Languages

  !insertmacro MUI_LANGUAGE "English"

; Show a custom splash screen on installer entry
Function .onInit
        InitPluginsDir
        File /oname=$PLUGINSDIR\splash.bmp "installer.bmp"

        splash::show 1000 $PLUGINSDIR\splash

        Pop $0 ; $0 has '1' if the user closed the splash screen early,
                        ; '0' if everything closed normally, and '-1' if some error occurred.
FunctionEnd

;--------------------------------
;Installer Sections

Section "Install Skype Plugin" SecSkypePlugin

  SetOutPath "$INSTDIR"

  ; Copy all of the required files (note the /r switch to recursively copy directories)
  File "SkypePlugin.exe"
  File "Tariffs.dat"
  File /r "..\docs"
  File "Skype4COM.dll"

  ; Register the COM server
  RegDLL Skype4COM.dll

  ;Store installation folder
  WriteRegStr HKCU "Software\Skype Plugin" "" $INSTDIR

  ;Create uninstaller
  WriteUninstaller "$INSTDIR\Uninstall.exe"

  ; Open the docs using the default (shell-assigned) browser
  ExecShell "open" "$INSTDIR\docs\html\index.html"

SectionEnd

; Optional section (can be disabled by the user)
Section "Start Menu Shortcuts"

  CreateDirectory "$SMPROGRAMS\Skype Plugin"
  CreateShortCut "$SMPROGRAMS\Skype Plugin\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
  CreateShortCut "$SMPROGRAMS\Skype Plugin\Skype Plugin.lnk" "$INSTDIR\SkypePlugin.exe" "" "$INSTDIR\SkypePlugin.exe" 0
  CreateShortCut "$SMPROGRAMS\Skype Plugin\Documentation.lnk" "$INSTDIR\docs\html\index.html" "" "$INSTDIR\docs\html\index.html" 0
SectionEnd


;--------------------------------
;Descriptions

  ;Language strings
  LangString DESC_SecSkypePlugin ${LANG_ENGLISH} "Skype Plugin Installation."

  ;Assign language strings to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${SecSkypePlugin} $(DESC_SecSkypePlugin)
  !insertmacro MUI_FUNCTION_DESCRIPTION_END

;--------------------------------
;Uninstaller Section

Section "Uninstall"

  Delete "$INSTDIR\Uninstall.exe"

  ; Unregister the COM server
  UnRegDLL "$INSTDIR\Skype4COM.dll"

  ; Delete all installed files
  RMDir "$INSTDIR"

  ; And registry entries
  DeleteRegKey /ifempty HKCU "Software\Skype Plugin"

  ; Remove shortcuts, if any
  Delete "$SMPROGRAMS\Skype Plugin\*.*"
  RMDir "$SMPROGRAMS\Skype Plugin"

SectionEnd

Some points of note:

  • The RegDLL and UnRegDLL directives will register and unregister a COM server on your behalf;
  • NSIS provides “hooks” at various points of the installer lifecycle. For instance, the splash screen in shown by the .onInit handler.
  • The ExecShell command (which seems to be a high-level wrapper around the ShellExecute function), can be used to open arbitrary files.

NSIS is a great application, and incredibly easy to pick up and use. The installers it produces are very slick looking, and can be extensively customised. It’s no wonder that this framework is now so popular.