; general defines

!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"

VIProductVersion "${PRODUCT_VERSION}"
;VIAddVersionKey "ProductName" "${PRODUCT_NAME}"
;VIAddVersionKey "Comments" "A test comment"
VIAddVersionKey "CompanyName" "${PRODUCT_PUBLISHER}"
VIAddVersionKey "LegalCopyright" "${PRODUCT_PUBLISHER}"
VIAddVersionKey "FileDescription" "${PRODUCT_NAME} Installer"
VIAddVersionKey "FileVersion" "${PRODUCT_VERSION}"

BrandingText "${PRODUCT_NAME} Installer"

SetCompressor /SOLID lzma

; MUI 1.67 compatible ------
!include "MUI.nsh"

; MUI Settings
; These lines tell NSIS to use the newer looking UI (aka the MUI)
!define MUI_ABORTWARNING
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
; Welcome page
!insertmacro MUI_PAGE_WELCOME
; License Screen
!insertmacro MUI_PAGE_LICENSE "${PRODUCT_NAME} license.txt"
; Directory page
!insertmacro MUI_PAGE_DIRECTORY
; Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES
; Language files
!insertmacro MUI_LANGUAGE "English"
; Reserve files
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS

; MUI end ------


Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "${PRODUCT_NAME} Installer.exe"
InstallDir "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
ShowUnInstDetails show


Section AdditionalDownloads
; Check for .NET Framework
  Call IsDotNETInstalled
   Pop $0
   StrCmp $0 1 checkforDirectX no.NETFramework
    no.NETFramework:
      MessageBox MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON1 ".NET Framework v1.1 w/ Hotfix 886903 or greater required before continuing.$\nDo you wish to install it?" IDYES Install.NETframework IDNO exit
    Install.NETframework:
      Banner::show /NOUNLOAD "Installing .NET Framework v1.1..."
      nsExec::ExecToStack "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}\optional\netfxsp1.exe"
      Banner::destroy
; Check for DirectX
   checkforDirectX:
   Call IsDirectXInstalled
   Pop $0
   StrCmp $0 1 done no.DirectX
   no.DirectX:
      MessageBox MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON1 "The DirectX for Managed Code April redistributable is required before continuing.$\nDo you wish to install it?" IDYES InstallDirectX IDNO exit
   InstallDirectX:
      Banner::show /NOUNLOAD "Installing DirectX..."
      nsExec::ExecToStack "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}\optional\DirectX9AprilRedist.exe"
      Banner::destroy
      goto done
   exit:
      abort
   done:
SectionEnd


Section "-a hidden section"
Push "C:\mylog.log"
Call DumpLog
SectionEnd


Section "MainSection" SEC01
; makes $SMPROGRAMS point to all suers
; note that only admins can write to all users
  SetShellVarContext all
  SetOutPath "$INSTDIR"
  File /r "..\Builds\${PRODUCT_NAME}_Rel\*"
  CreateDirectory "$SMPROGRAMS\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
  CreateShortCut "$SMPROGRAMS\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}\${PRODUCT_NAME} Help.lnk" "$INSTDIR\${PRODUCT_NAME}.chm"
  CreateShortCut "$SMPROGRAMS\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe"
  CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe"
SectionEnd


Section -AdditionalIcons
; makes $SMPROGRAMS point to all suers
; note that only admins can write to all users
  SetShellVarContext all
  CreateShortCut "$SMPROGRAMS\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}\Uninstall ${PRODUCT_NAME}.lnk" "$INSTDIR\uninst.exe"
SectionEnd


Section -Post
  WriteUninstaller "$INSTDIR\uninst.exe"
  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\${PRODUCT_NAME}.exe"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_NAME}.exe"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
  RMDir /r /REBOOTOK "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}\optional"
SectionEnd


Section Uninstall
; makes $SMPROGRAMS point to all suers
; note that only admins can write to all users
  SetShellVarContext all
; Remove all subdirs except DataStore
  Push "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
  Push "DataStore"
  Call un.RmDirsButOne
; Remove all subfiles except dummy
  Push "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
  Push ""
  Call un.RmFilesButOne
; If after all of the above and the dir is still empty, delete product_name and product_publisher
  StrCpy $0 "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
  Call un.DeleteDirIfEmpty
  StrCpy $0 "$PROGRAMFILES\${PRODUCT_PUBLISHER}"
  Call un.DeleteDirIfEmpty
  Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
  RMDir /r "$SMPROGRAMS\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
; Only remove empty dirs
  StrCpy $0 "$SMPROGRAMS\${PRODUCT_PUBLISHER}"
  Call un.DeleteDirIfEmpty
  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
  SetAutoClose true
SectionEnd


Function .onInit
;Prevent Multiple installer instances
  System::Call 'kernel32::CreateMutexA(i 0, i 0, t "myMutex") i .r1 ?e'
  Pop $R0
  StrCmp $R0 0 +3
   MessageBox MB_OK|MB_ICONEXCLAMATION "The ${PRODUCT_NAME} installer is already running."
   Abort
FunctionEnd


Function un.onUninstSuccess
  HideWindow
  MessageBox MB_ICONINFORMATION|MB_OK "${PRODUCT_NAME} was successfully removed from your computer."
FunctionEnd


Function un.onInit
  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove ${PRODUCT_NAME}?" IDYES +2
  Abort
FunctionEnd


Function IsDirectXInstalled
; Usage:
; Call IsDirectXInstalled
; Pop $0
; StrCmp $0 1 found.DirectX no.DirectX
  Push $0
  IfFileExists "$WINDIR\assembly\GAC\Microsoft.DirectX.Direct3D\1.0.2902.0__31bf3856ad364e35\Microsoft.DirectX.Direct3D.dll" foundDX noDX
  foundDX:
  StrCpy $0 1
  goto done
  noDX:
  StrCpy $0 0
  goto done
  done:
  Pop $1
FunctionEnd


Function IsDotNETInstalled
; Usage:
; Call IsDotNETInstalled
; Pop $0
; StrCmp $0 1 found.NETFramework no.NETFramework
   Push $0
   Push $1
   Push $2
   Push $3
   Push $4
   ReadRegStr $4 HKEY_LOCAL_MACHINE \
     "Software\Microsoft\.NETFramework" "InstallRoot"
   # remove trailing back slash
   Push $4
   Exch $EXEDIR
   Exch $EXEDIR
   Pop $4
   # if the root directory doesn't exist .NET is not installed
   IfFileExists $4 0 noDotNET
   StrCpy $0 0
   EnumStart:
     EnumRegKey $2 HKEY_LOCAL_MACHINE \
       "Software\Microsoft\.NETFramework\Policy\"  $0
     IntOp $0 $0 + 1
     StrCmp $2 "" noDotNET
     StrCpy $1 0
     EnumPolicy:
       EnumRegValue $3 HKEY_LOCAL_MACHINE \
         "Software\Microsoft\.NETFramework\Policy\$2" $1
       IntOp $1 $1 + 1
        StrCmp $3 "" EnumStart
         IfFileExists "$4\$2.$3" checkDotNETver EnumPolicy
   noDotNET:
     StrCpy $0 0
     Goto done
   checkDotNETver:
     ; Change the integer below to change the version of .NET Framework above which a 1 is returned
     IntCmp $3 4322 foundDotNET noDotNET foundDotNET
   foundDotNET:
     StrCpy $0 1
   done:
     Pop $4
     Pop $3
     Pop $2
     Pop $1
     Exch $0
FunctionEnd


Function un.RmDirsButOne
; Usage
; Push "main dir path"
; Push "dir to exclude"
; Call RmDirsButOne
 Exch $R0 ; exclude dir
 Exch
 Exch $R1 ; route dir
 Push $R2
 Push $R3
  FindFirst $R3 $R2 "$R1\*.*"
  IfErrors Exit
  Top:
   StrCmp $R2 "." Next
   StrCmp $R2 ".." Next
   StrCmp $R2 $R0 Next
   IfFileExists "$R1\$R2\*.*" 0 Next
    RmDir /r "$R1\$R2"
   #Goto Exit ;uncomment this to stop it being recursive
   Next:
    ClearErrors
    FindNext $R3 $R2
    IfErrors Exit
   Goto Top
  Exit:
  FindClose $R3
 Pop $R3
 Pop $R2
 Pop $R1
 Pop $R0
FunctionEnd


Function un.RmFilesButOne
 Exch $R0 ; exclude file
 Exch
 Exch $R1 ; route dir
 Push $R2
 Push $R3
  FindFirst $R3 $R2 "$R1\*.*"
  IfErrors Exit
  Top:
   StrCmp $R2 "." Next
   StrCmp $R2 ".." Next
   StrCmp $R2 $R0 Next
   IfFileExists "$R1\$R2\*.*" Next
    Delete "$R1\$R2"
   #Goto Exit ;uncomment this to stop it being recursive
   Next:
    ClearErrors
    FindNext $R3 $R2
    IfErrors Exit
   Goto Top
  Exit:
  FindClose $R3
 Pop $R3
 Pop $R2
 Pop $R1
 Pop $R0
FunctionEnd


Function un.DeleteDirIfEmpty
; usage:
; StrCpy $0 "Directory to delete"
; Call un.DeleteDirIfEmpty
  FindFirst $R0 $R1 "$0\*.*"
  strcmp $R1 "." 0 NoDelete
   FindNext $R0 $R1
   strcmp $R1 ".." 0 NoDelete
    ClearErrors
    FindNext $R0 $R1
    IfErrors 0 NoDelete
     FindClose $R0
     Sleep 1000
     RMDir "$0"
  NoDelete:
   FindClose $R0
FunctionEnd


!define LVM_GETITEMCOUNT 0x1004
!define LVM_GETITEMTEXT 0x102D

Function DumpLog
  Exch $5
  Push $0
  Push $1
  Push $2
  Push $3
  Push $4
  Push $6

  FindWindow $0 "#32770" "" $HWNDPARENT
  GetDlgItem $0 $0 1016
  StrCmp $0 0 exit
  FileOpen $5 $5 "w"
  StrCmp $5 "" exit
    SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
    System::Alloc ${NSIS_MAX_STRLEN}
    Pop $3
    StrCpy $2 0
    System::Call "*(i, i, i, i, i, i, i, i, i) i \
      (0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
    loop: StrCmp $2 $6 done
      System::Call "User32::SendMessageA(i, i, i, i) i \
        ($0, ${LVM_GETITEMTEXT}, $2, r1)"
      System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
      FileWrite $5 "$4$\r$\n"
      IntOp $2 $2 + 1
      Goto loop
    done:
      FileClose $5
      System::Free $1
      System::Free $3
  exit:
    Pop $6
    Pop $4
    Pop $3
    Pop $2
    Pop $1
    Pop $0
    Exch $5
FunctionEnd