Naracea 1.1.2: Installing .NET Framework as part of installation process
There is new version of Naracea available: version 1.1.2. What is new in this version? I replaced installer. For versions prior to 1.1.2, Naracea was distributed as MSI file, which is Microsoft Installer package, for 1.1.2 and further I’m using NSIS, which generates EXE file which installs the application.
Why did I change the installer? Well, because with NSIS I can easily bootstrap .NET Framework for computers which do not have it installed. With MSI file, you either need to have .NET 4.0 installed on your computer already, or you need to go to Microsoft download page and install it manually. It is somehow annoying, to try to install the application, then being interrupted by some messagebox which tells you that you need to do something else, before you can continue.
Therefore I decide it is time to get over this, and change the installer.
Don’t get me wrong: MSI is not that bad if you have right tools to author it. By “right tools” I mean WixSharp, which allows you to write installers in C#, which is much more convenient that using original Wix, which requires writing cryptic XML files. The problem with MSI is, that you cannot write single file installer (as far as I know), which would check whether you have .NET 4.0 installed and download it and install in case you don’t.
Thus I was looking for something to overcome this limitation, and from available options, NSIS looks the best.
Now I’ll describe shortly what I do to build this new installer.
First of all, I have file “VERSION” in my project folder, which contains current version of the application without build version. The build version (that last number which is attached to the end of the installer’s file name) is generated by the rake script when I start build process, and it consists of last two digits of the year (so for builds done in year 2012 it is 12), and from number of the day in current year (so build 121 was build on the January 1st of 2012).
Now, for NSIS install file I need this exact release version, so it can be attached to installer’s file name and to be set in Windows registry entry, which shows Naracea in “Install Programs and Features” control panel.
Following rake tasks generates “VERSION.nsh” from VERSION file with full version number and runs makensis.exe program which processes installer script and generates installer EXE file:
task :pack_release do | task| puts 'packing release files...' ver = "0" File.open("VERSION", "rb") do |file| ver = file.read end ver = ver + "." + get_build_version() File.open("VERSION.nsh", "w") do |file| file.write("!define VERSION \"") file.write(ver) file.write("\"") end system '_tools\nsis\makensis.exe naracea.nsi' end def get_build_version() return Date.today.year.to_s[2..4] + Date.today.yday.to_s end
To run this task you need to have NSIS in folder “_tools\nsis\” (relative path from where you run the rake). When getting NSIS, download and install plugin Inetc, which is needed by installer for file download (in this case .NET Framework 4.0 installer).
Now we are ready to write the NSIS installer script, which will check whether .NET 4.0 is installed, and if it isn’t, it will download it and install (I removed mentions of Naracea from it, because some people tend to copy and paste stuff from internet without thing about it):
;-------------------------------- ;Include Modern UI !include "MUI2.nsh" !include "FileFunc.nsh" !include "VERSION.nsh" !include WordFunc.nsh !insertmacro VersionCompare !include LogicLib.nsh ;-------------------------------- ;General ;Name and file Name "<product>" ; "_build" is folder into which your application installer will be build into OutFile "_build\<product>-${VERSION}.exe" ;Request application privileges for Windows Vista/7 RequestExecutionLevel admin ;Additional settings CRCCheck on !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\<product>" ;Icon ;"_icons" is folder where you have your application icon stored !define MUI_ICON "_icons\icon.ico" ;Default installation folder InstallDir "$PROGRAMFILES\<product>" ;Get installation folder from registry if available InstallDirRegKey HKCU "Software\<product>" "" ;Remove "Nullsoft Install System" text BrandingText " " ;-------------------------------- ;Interface Settings !define MUI_ABORTWARNING ;-------------------------------- ;Pages ; "_texts" is folder where you license file is stored !insertmacro MUI_PAGE_LICENSE "_texts\License.rtf" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ;Functions checking for .NET presence Var InstallDotNET Function .onInit ;Here we check for Client .NET 4.0 profile. To check for Full .NET 4.0, replace "Client" with "Full" ReadRegDWORD $0 HKLM 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client' Install ${If} $0 == '' StrCpy $InstallDotNET "Yes" MessageBox MB_OK|MB_ICONINFORMATION "<product> requires that the Microsoft .NET Framework 4.0 is installed. The Microsoft .NET Framework will be downloaded and installed automatically during installation of <product>." Return ${EndIf} FunctionEnd ;-------------------------------- ;Installer Sections Section "<product>" SecDummy SetOutPath "$INSTDIR" ; Get .NET if required ${If} $InstallDotNET == "Yes" inetc::get /caption "Downloading Microsoft .NET Framework 4.0" /canceltext "Cancel" "<http://URL.to.NET4.0.installer.exe>" "$TEMP\dotnetfx40.exe" /end Pop $1 ${If} $1 != "OK" Delete "$TEMP\dotnetfx40.exe" Abort "Installation cancelled." ${EndIf} ExecWait "$TEMP\dotnetfx40.exe" Delete "$TEMP\dotnetfx40.exe" ${EndIf} ;Files to be installed ; "_build" is folder into which your application files are being built into File "_build\<product>\<product>.exe" ;Create shortcuts SetShellVarContext all CreateDirectory "$SMPROGRAMS\<product>" CreateShortCut "$SMPROGRAMS\<product>\<product>.lnk" "$INSTDIR\<product>.exe" CreateShortCut "$SMPROGRAMS\<product>\Uninstall <product>.lnk" "$INSTDIR\Uninstall.exe" ;Store installation folder WriteRegStr HKCU "Software\<product>" "" $INSTDIR WriteRegStr SHCTX "${UNINST_KEY}" "DisplayName" "<product>" WriteRegStr SHCTX "${UNINST_KEY}" "Publisher" "<author>" WriteRegStr SHCTX "${UNINST_KEY}" "DisplayVersion" "${VERSION}" WriteRegStr SHCTX "${UNINST_KEY}" "DisplayIcon" "$\"$INSTDIR\<product>.exe$\",0" ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 IntFmt $0 "0x%08X" $0 WriteRegDWORD SHCTX "${UNINST_KEY}" "EstimatedSize" "$0" WriteRegStr SHCTX "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr SHCTX "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" SectionEnd ;-------------------------------- ;Uninstaller Section Section "Uninstall" ;Remove files from installation folder ;List all installed files here Delete "$INSTDIR\<product>.exe" Delete "$INSTDIR\Uninstall.exe" ;Remove installation folder RMDir /r "$INSTDIR" ;Remove links from startmenu SetShellVarContext all Delete "$SMPROGRAMS\<product>\Uninstall <product>.lnk" Delete "$SMPROGRAMS\<product>\<product>.lnk" RMDir /r "$SMPROGRAMS\<product>" DeleteRegKey /ifempty HKCU "Software\<product>" DeleteRegKey SHCTX "${UNINST_KEY}" SectionEnd
Of course, you need to replace all occurrences of product with name of your application, and http://URL.to.NET4.0.installer.exe with URL to where the .NET 4.0 can be downloaded from.
And now you have your NSIS install script ready to build installer for your .NET application.
And don’t forget to give new Naracea a try!