Since I got SmarterMeter working in Windows in my last post, the next step was to make it easier to install. After searching for the best way to make an installer, I ended up using NSIS which is a Free Software Windows installation builder. It allows application authors to create installers that look and act like traditional Windows installers but with Free Software that runs on any platform rather than expensive Windows only software.

Not knowing anything about how NSIS worked I started with their tutorials. While they did work, the look and feel didn’t match a traditional installer. Since it was important to me that the installer felt native to the user, I continued to search for a better tutorial. It turns out that there is a whole plugin system for NSIS and one of the plugins is called Modern User Interface.

Using the examples as guides I was able to create a working installer for SmarterMeter that was both functional and matched my expectations. If you want to create one for your project, feel free to use smartermeter’s as a starting point.

!include "MUI2.nsh"

Name "Smartermeter (${VERSION})"
OutFile "../pkg/smartermeter-${VERSION}.exe"

InstallDir "$PROGRAMFILES\SmarterMeter"

InstallDirRegKey HKCU "Software\SmarterMeter" ""

;Request application privileges for Windows Vista
RequestExecutionLevel user

!define MUI_ABORTWARNING
!define MUI_ICON "../icons/smartermeter.ico"

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!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"

Section "Smartermeter Base" SecBase
  SetOutPath "$INSTDIR"

  File /r "../pkg/base/*"

  CreateDirectory "$SMPROGRAMS\SmarterMeter"
  CreateShortCut "$SMPROGRAMS\SmarterMeter\SmarterMeter.lnk" "$INSTDIR\smartermeter.exe"
  CreateShortCut "$SMPROGRAMS\SmarterMeter\Uninstall.lnk" "$INSTDIR\uninstall.exe"

  ;Store installation folder
  WriteRegStr HKCU "Software\Smartermeter" "" $INSTDIR

  ;Create uninstaller
  WriteUninstaller "$INSTDIR\uninstall.exe"
SectionEnd

;Language strings
LangString DESC_SecBase ${LANG_ENGLISH} "The smartermeter application."

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

Section "Uninstall"
  Delete "$INSTDIR\*.rb"
  Delete "$INSTDIR\*.jar"
  Delete "$INSTDIR\*.exe"
  RMDIR  /r "$INSTDIR\gems"
  RMDIR  /r "$INSTDIR\icons"
  RMDIR  /r "$INSTDIR\smartermeter"

  Delete "$SMPROGRAMS\Smartermeter\Smartermeter.lnk"
  Delete "$SMPROGRAMS\Smartermeter\Uninstall.lnk"
  RMDIR "$SMPROGRAMS\Smartermeter"

  RMDir "$INSTDIR"

  DeleteRegKey /ifempty HKCU "Software\Smartermeter"
SectionEnd

Once I had the installer working, I then began work on creating an executable wrapper. While it’s possible to run JRuby in jar under Windows by simply double clicking, it doesn’t act the same way that a traditional application does. So I went looking for a project that would create a simple executable that would in turn launch the jar but act just like an application. It turns out that Launch4J does exactly that. Below is the configuration file that SmarterMeter uses.

<launch4jConfig>
  <dontWrapJar>true</dontWrapJar>
  <headerType>console</headerType>
  <jar>jruby-complete.jar</jar>
  <outfile>../pkg/base/smartermeter.exe</outfile>
  <errTitle></errTitle>
  <cmdLine>main.rb</cmdLine>
  <chdir>.</chdir>
  <priority>normal</priority>
  <downloadUrl>http://java.com/download</downloadUrl>
  <supportUrl></supportUrl>
  <customProcName>true</customProcName>
  <stayAlive>false</stayAlive>
  <manifest></manifest>
  <icon>../icons/smartermeter.ico</icon>
  <var>GEM_HOME=gems</var>
  <singleInstance>
    <mutexName>smartermeter</mutexName>
    <windowTitle>Smartermeter</windowTitle>
  </singleInstance>
  <jre>
    <path></path>
    <minVersion>1.6.0</minVersion>
    <maxVersion></maxVersion>
    <jdkPreference>preferJre</jdkPreference>
  </jre>
</launch4jConfig>

Overall I am very happy with the native integration I was able to achieve with these two tools in a short amount of time.