setup.nsi

;
; NSIS install script for project Lesson2
; Compiling with MakeNSIS will create a setup.exe file

; Global settings ------------------------------------------------------------

!define PROJ_NAME "Lesson2"
!define PROJ_VER "1.0"
!define AUTHOR "Jim Detwiler"
!define DLL_PATH "C:\geog489\Lesson2\Lesson2\bin\Release\"
!define DLL_NAME "Lesson2.dll"
!define INSTALLER "setup_v${PROJ_VER}.exe"
!define UNINSTALLER "uninstall.exe"
!define START_DIR "Programs\${PROJ_NAME} ${PROJ_VER}"
!define DOT_NET_VER "v2.0" ; required version of the .NET framework

!define REG_SUBKEY "Software\${PROJ_NAME}"
!define REG_KEY_INSTALLDIR "InstallDir"
!define REG_UNINSTALL_ROOT "Software\Microsoft\Windows\CurrentVersion\Uninstall"

!define DEBUG_LOG "${PROJ_NAME}-debug.log"
!define REGISTER_LOG "regasm.log"

!define DLL_REGISTER_OK "Types registered successfully$\r$\n"

OutFile "${INSTALLER}"
Name "${PROJ_NAME}"
Caption "${PROJ_NAME} v${PROJ_VER} Setup"
InstallDir "$PROGRAMFILES\${PROJ_NAME}"
InstallDirRegKey HKLM "${REG_SUBKEY}" "${REG_KEY_INSTALLDIR}"
SetCompressor "lzma"
CompletedText "Completed and verified."
XPStyle "On"
InstallColors /windows

; Install --------------------------------------------------------------------

Page directory
Page instfiles
ShowInstDetails "hide"

Section "Install"
    DetailPrint "Installing ${PROJ_NAME} v${PROJ_VER}"
    SetOutPath "$INSTDIR"

    ; save our install location to the registry
    WriteRegStr HKLM "${REG_SUBKEY}" "${REG_KEY_INSTALLDIR}" "$INSTDIR"
    DetailPrint "Install dir saved to registry"

    ; create uninstaller first, so user can clean up if we barf
    WriteUninstaller "$INSTDIR\${UNINSTALLER}"

    ; copy our DLL
    File "${DLL_PATH}${DLL_NAME}"

    ; create start menu shortcuts
    ; SetShellVarContext all
    ; CreateDirectory "$STARTMENU\${START_DIR}"
    ; SetOutPath "$STARTMENU\${START_DIR}"
    ; CreateShortCut "Uninstall.lnk" "$INSTDIR\${UNINSTALLER}"

    ; register us in the 'add/remove programs' list
    WriteRegStr HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}" \
        "DisplayName" "${PROJ_NAME} v${PROJ_VER}"
    WriteRegStr HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}" \
        "UninstallString" "$INSTDIR\${UNINSTALLER}"
    WriteRegStr HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}" \
        "Publisher" "${AUTHOR}"
    WriteRegStr HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}" \
        "DisplayVersion" "${PROJ_VER}"
    WriteRegStr HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}" \
        "NoModify" 1
    WriteRegStr HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}" \
        "NoRepair" 1
    DetailPrint "Registered with add/remove programs"

    ; get directory of .NET framework installation
    Push "${DOT_NET_VER}"
    Call GetDotNetDir
    Pop $R0 ; .net framework installation directory
    StrCmpS "" "$R0" err_dot_net_not_found
    DetailPrint ".Net ${DOT_NET_VER} dir: $R0"

    ; call RegAsm to register our .NET assembly DLL with COM
    GetFullPathName /SHORT $1 $R0
    GetFullPathName /SHORT $2 $INSTDIR
    StrCpy $0 '"$1\RegAsm.exe" /codebase /nologo "$2\${DLL_NAME}"'
    DetailPrint $0
    nsExec::ExecToLog $0
    pop $0
    IntCmp $0 0 install_end

    MessageBox MB_OK|MB_ICONEXCLAMATION|MB_DEFBUTTON1 \
        "Failed to register ${DLL_NAME}. Install aborted."
    Abort "Aborted: Failed to register ${DLL_NAME}."

err_dot_net_not_found:

    MessageBox MB_OK|MB_ICONEXCLAMATION|MB_DEFBUTTON1 \
        "Can't find the .Net framework ${DOT_NET_VER}.$\nYou must install it first. It can be $\ndowloaded for free from microsoft.com."
    Abort "Aborted: .Net framework ${DOT_NET_VER} not found."

install_end:
SectionEnd


; Given a .NET version number, this function returns that .NET framework's
; install directory. Returns "" if the given .NET version is not installed.
; Params: [version] (eg. "v2.0")
; Return: [dir] (eg. "C:\WINNT\Microsoft.NET\Framework\v2.0.50727")
Function GetDotNetDir
    Exch $R0 ; Set R0 to .net version major
    Push $R1
    Push $R2

    ; set R1 to minor version number of the installed .NET runtime
    EnumRegValue $R1 HKLM \
        "Software\Microsoft\.NetFramework\policy\$R0" 0
    IfErrors getdotnetdir_err

    ; set R2 to .NET install dir root
    ReadRegStr $R2 HKLM \
        "Software\Microsoft\.NetFramework" "InstallRoot"
    IfErrors getdotnetdir_err

    ; set R0 to the .NET install dir full
    StrCpy $R0 "$R2$R0.$R1"

getdotnetdir_end:
    Pop $R2
    Pop $R1
    Exch $R0 ; return .net install dir full
    Return

getdotnetdir_err:
    DetailPrint "ERROR: failed to find .Net $R0 runtime"
    StrCpy $R0 ""
    Goto getdotnetdir_end

FunctionEnd


;==Uninstall==================================================================

UninstPage uninstConfirm
UninstPage instfiles
ShowUninstDetails "hide"


Section "Uninstall"

    ; get directory of .NET framework installation
    Push ${DOT_NET_VER}
    Call Un.GetDotNetDir
    Pop $R0 ; .net framework installation directory
    StrCmpS "" $R0 err_dot_net_not_found

    ; delete entry from 'add/remove programs'
    DeleteRegKey HKLM "${REG_UNINSTALL_ROOT}\${PROJ_NAME}"
   
    ; remove all start menu shortcuts
    ; SetShellVarContext all
    ; Delete "$STARTMENU\${START_DIR}\*"
    ; RMDir "$STARTMENU\${START_DIR}"

    ; perform the uninstall
    ExpandEnvStrings $0 %COMSPEC%
    StrCpy $2 '$INSTDIR\${REGISTER_LOG}'
    StrCpy $1 '$R0\RegAsm.exe /u /codebase /nologo ${DLL_NAME} >"$2" 2>&1'
    ExecWait '"$0" /C $1'
    ; display regasm output in detail log
    Push "$2"
    Call un.DetailPrintFile

    ; delete files
    Delete "$INSTDIR\${DEBUG_LOG}"
    Delete "$INSTDIR\${REGISTER_LOG}"
    Delete "$INSTDIR\${DLL_NAME}"
    Delete "$INSTDIR\${UNINSTALLER}"
    RMDir "$INSTDIR"

    Goto uninstall_end

err_dot_net_not_found:

    MessageBox MB_OK|MB_ICONEXCLAMATION|MB_DEFBUTTON1 \
        "Can't find the .Net framework ${DOT_NET_VER}.$\nI can't perform a clean uninstall without it.$\nDownload the .Net framework ${DOT_NET_VER}$\nredistributable from Microsoft, run it, then$\nretry this uninstall."
    Abort "Aborted: .Net framework ${DOT_NET_VER} not found."

uninstall_end:
SectionEnd

; This function is an exact copy of 'GetDotNetDir'.
; All functions called from the uninstall section have to be called
; 'un.xxxxx', and cannot call or be called by functions from the install.
Function un.GetDotNetDir
    Exch $R0 ; Set R0 to .net version major
    Push $R1
    Push $R2

    ; set R1 to minor version number of the installed .NET runtime
    EnumRegValue $R1 HKLM \
        "Software\Microsoft\.NetFramework\policy\$R0" 0
    IfErrors getdotnetdir_err

    ; set R2 to .NET install dir root
    ReadRegStr $R2 HKLM \
        "Software\Microsoft\.NetFramework" "InstallRoot"
    IfErrors getdotnetdir_err

    ; set R0 to the .NET install dir full
    StrCpy $R0 "$R2$R0.$R1"

getdotnetdir_end:
    Pop $R2
    Pop $R1
    Exch $R0 ; return .net install dir full
    Return

getdotnetdir_err:
    StrCpy $R0 ""
    Goto getdotnetdir_end

FunctionEnd


; an exact copy of function 'DetailPrintFile'
; NSIS does not allow functions defined in the installer section to be called
; during uninstall. This copy is defined just for the uninstaller.
Function un.DetailPrintFile
    Exch $0 ; filename to spool to Details log
    Push $1
    Push $2

    ClearErrors
    FileOpen $1 $0 r
next_line:
    FileRead $1 $2
    IfErrors eof
    ; strip newline chars
    StrCpy $2 $2 -2
    DetailPrint $2
    goto next_line

eof:
    FileClose $1
    Pop $2
    Pop $1
    Pop $0
FunctionEnd