En varias ocasiones he mencionado el instalador NSIS (Nullsoft Scriptable Install System), y aunque ya hace bastante tiempo de ello, no había tenido la oportunidad de dedicarle un artículo completo.

Sin embargo a raíz del nuevo instalador de FileOptimizer y algunos proyectos profesionales, he vuelto a trabajar con él.

NSIS es un instalador basado en scripts, con un lenguaje de programación que mezcla primitivas de muy alto nivel, con otras de muy bajo nivel. De modo que algunas operaciones son realmente sencillas, y otras bastante tediosas.

Sus orígenes se remontan a 1998 cuando Justin Frankel, lo desarrolló como herramienta de instalación para su Winamp. Mucho antes de ser comprado por AOL, y por supuesto de que dejara de existir.

Es una herramienta de código abierto para Windows, que genera unos instaladores muy compactos, gracias a lo ligero de sun runtime, del orden de 50 Kb., y lo eficaz de la compresión LZMA, aunque si se quiere puede ser Deflate.

Su desarrollo ha ido bastante a trompicones, de manera que estuvimos anclados a la versión 2.46 desde 2009. Sin embargo en 2013, el proyecto se retomó, por lo que ahora tenemos ya la beta 0 de la versión 3, que después de 3 alfas, nos ofrece soporte unicode, y Windows 8.x. Aunque ya es capaz de generar instaladores compatibles Win64, se espera permita generar también instaladores nativos para dicha plataforma.

La filosofía de trabajo se basa en la linea de comandos (makensis), o bien en un IDE (makensisw), que no obstante, siempre requieren escribir el código desde un editor de textos externo. La sintaxis del lenguaje es parecida a C, incluso con su preprocesador.

Como decía antes, el trabajo con el contenido del instalador, es sencillo, con funciones para extraer a una carpeta, gestionar directorios, crear accesos directos, etc. Crear el desinstalador es un proceso que hace automáticamente el programa, nosotros solamente tendremos que indicarle los procesos a realizar. A partir de ahí, todo se complica. Desde crear la entrada correspondiente en Agregar y quitar programas del Panel de control, a detectar si estamos en un entorno x86 o x64. Como la mejor forma de explicarlo es con un ejemplo, os lo muestro a continuación la última versión del FileOptimizerSetup.nsi, el script usado en FileOptimizer.

; -------------------------------------------------------------------------------------------------
SetCompressor /SOLID /FINAL lzma 
SetCompressorDictSize 128
Unicode true
 
 
 
; -------------------------------------------------------------------------------------------------
!include "MUI.nsh"
!define MUI_ABORTWARNING
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!include x64.nsh
 
 
 
; -------------------------------------------------------------------------------------------------
!define APP_NAME 	"FileOptimizer"
!define APP_DESCRIPTION	"Lossless file size optimizer"
!define APP_COMPANY	"Javier Gutiérrez Chamorro (Guti)"
!define APP_COPYRIGHT	"© Copyright 2012-2014 by Javier Gutiérrez Chamorro (Guti)"
!define APP_WEB		"http://nikkhokkho.sourceforge.net/static.php?page=FileOptimizer"
!define APP_VERSION 	"6.9.0.0"
 
 
 
; -------------------------------------------------------------------------------------------------
Icon "..\${APP_NAME}.ico"
;UninstallIcon "..\${APP_NAME}.ico"
OutFile "..\${APP_NAME}Setup.exe"
Name "${APP_NAME}"
InstallDir "$PROGRAMFILES\${APP_NAME}"
InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "InstallDir"
 
 
 
; -------------------------------------------------------------------------------------------------
Function .onInit
        ${If} ${RunningX64}
        	${EnableX64FSRedirection}
		StrCpy '$INSTDIR' "$PROGRAMFILES64\${APP_NAME}"
        ${EndIf}
FunctionEnd
 
 
 
; -------------------------------------------------------------------------------------------------
Section "Files"
	CreateDirectory "$SMPROGRAMS\FileOptimizer"
 
	SetOutPath $INSTDIR
	File ..\Win32\Release\*.chm
	CreateDirectory "$SMPROGRAMS\${APP_NAME}";
	${If} ${RunningX64}
		File ..\Win32\Release\*64.exe
		SetOutPath $INSTDIR\Plugins64
		File /r ..\Win32\Release\Plugins64\*.*
		CreateShortCut "$SMPROGRAMS\${APP_NAME}\Launch ${APP_NAME}.lnk" "$INSTDIR\${APP_NAME}64.exe" "" "" "" SW_SHOWNORMAL "" "Launch ${APP_NAME}"
		CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${APP_NAME}64.exe" "" "" "" SW_SHOWNORMAL "CONTROL|ALT|x" "Launch ${APP_NAME}"
		CreateShortCut "$QUICKLAUNCH\${APP_NAME}.lnk" "$INSTDIR\${APP_NAME}64.exe" "" "" "" SW_SHOWNORMAL "CONTROL|ALT|x" "Launch ${APP_NAME}"
	${Else}
		File ..\Win32\Release\*32.exe
		SetOutPath $INSTDIR\Plugins32
		File /r ..\Win32\Release\Plugins32\*.*
		CreateShortCut "$SMPROGRAMS\${APP_NAME}\Launch ${APP_NAME}.lnk" "$INSTDIR\${APP_NAME}32.exe" "" "" "" SW_SHOWNORMAL "" "Launch ${APP_NAME} x86"
		CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${APP_NAME}32.exe" "" "" "" SW_SHOWNORMAL "CONTROL|ALT|x" "Launch ${APP_NAME} x86"
		CreateShortCut "$QUICKLAUNCH\${APP_NAME}.lnk" "$INSTDIR\${APP_NAME}32.exe" "" "" "" SW_SHOWNORMAL "CONTROL|ALT|x" "Launch ${APP_NAME} x86"
	${EndIf}
 
	WriteUninstaller "$INSTDIR\Uninstall.exe"
 
	CreateShortCut "$SMPROGRAMS\${APP_NAME}\Help.lnk" "$INSTDIR\${APP_NAME}.chm" "" "" "" SW_SHOWNORMAL "" "View ${APP_NAME} Help"
	CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "" "" SW_SHOWNORMAL "" "Uninstall ${APP_NAME}"
	CreateShortCut "$FAVORITES\${APP_NAME} Home Page.lnk" "${APP_WEB}" "" "" "" "" "" "Visit ${APP_NAME} Home Page"
 
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "DisplayName" "${APP_NAME}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "Publisher" "${APP_COMPANY}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "DisplayVersion" "${APP_VERSION}"
 
	${If} ${RunningX64}
		WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "DisplayIcon" "$\"$INSTDIR\${APP_NAME}64.exe$\""
	${Else}
		WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "DisplayIcon" "$\"$INSTDIR\${APP_NAME}32.exe$\""
	${EndIf}
 
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "ProductID" "${APP_NAME} ${APP_VERSION}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "RegCompany" "${APP_COMPANY}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "RegOwner" "${APP_COPYRIGHT}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "URLInfoAbout" "${APP_WEB}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "URLUpdateInfo" "${APP_WEB}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "HelpLink" "${APP_WEB}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "Comments" "${APP_DESCRIPTION}"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "InstallDir" "($INSTDIR)"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "NoModify" "1"
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "NoRepair" "1"
 	!include "FileFunc.nsh"
	${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
	IntFmt $0 "0x%08X" $0
	WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "EstimatedSize" "$0"
SectionEnd
 
 
 
; -------------------------------------------------------------------------------------------------
Section "Uninstall"
	RMDir /r "$INSTDIR"
	RmDir /r "$SMPROGRAMS\${APP_NAME}"
	Delete "$PROFILE\${APP_NAME}.ini"
	Delete "$DESKTOP\${APP_NAME}.lnk"
	Delete "$QUICKLAUNCH\${APP_NAME}.lnk"
	Delete "$FAVORITES\${APP_NAME} Home Page.lnk"
	DeleteRegKey HKCU "Software\${APP_NAME}"	;Not needed because we do not write on the registry.
	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
SectionEnd
 
 
 
; -------------------------------------------------------------------------------------------------
VIProductVersion "${APP_VERSION}"
	VIAddVersionKey "ProductName" "${APP_NAME}"
	VIAddVersionKey "InternalName" "${APP_NAME}.exe"
	VIAddVersionKey "Comments" "Get more info at ${APP_WEB}"
	VIAddVersionKey "CompanyName" "${APP_COMPANY}"
	VIAddVersionKey "LegalTrademarks" "${APP_COPYRIGHT}"
	VIAddVersionKey "LegalCopyright" "${APP_COPYRIGHT}"
	VIAddVersionKey "FileDescription" "${APP_DESCRIPTION}"
	VIAddVersionKey "FileVersion" "${APP_VERSION}"

Vemos bastantes cosas destacables, como el manifest con la versión del instalador (VIProductVersion); el uso de la cabecera FileFunc.nsh para obtener el tamaño total de los archivos instalados, …

Para el manejo de la interfaz de usuario, te recomiendo incluir MUI.nsh, que da acceso al Modern User Interface, no solamente es más atractivo, sino también mucho más fácil de utilizar que los diálogos tradicionales.

Lo tienes disponible en la página de descargas. Luego podrás consultar la documentación online, o bien desde el archivo CHM incluido. Si necesitas más ejemplos, plugins, o macros, las tienes en el centro de desarrollo.