; CPack install script designed for a nmake build

;--------------------------------
; You must define these values

  !define VERSION "@CPACK_PACKAGE_VERSION@"
  !define PATCH  "@CPACK_PACKAGE_VERSION_PATCH@"
  !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"

;--------------------------------
; Default file extensions and ftypes
!define DefRexxExt       ".rex"
!define DefRexxFType     "RexxScript"
!define DefRexxHideExt   ".rexg"
!define DefRexxHideFType "RexxHide"
!define DefRexxPawsExt   ".rexp"
!define DefRexxPawsFType "RexxPaws"

;--------------------------------
;Variables

  Var MUI_TEMP
  Var STARTMENU_FOLDER
  Var SV_ALLUSERS
  Var START_MENU
  Var DO_NOT_ADD_TO_PATH
  Var ADD_TO_PATH_ALL_USERS
  Var ADD_TO_PATH_CURRENT_USER
  Var INSTALL_DESKTOP
  Var IS_DEFAULT_INSTALLDIR

  Var IsAdminUser                ; is the installer being run by an admin:           true / false
  Var RxapiIsService             ; is rxapi installed as a service:                  true / false
  Var RxapiIsRunning             ; is rxapi running:                                 true / false

  ;
  Var RegVal_uninstallString     ; uninstall string (program) found in regsitry
  Var RegVal_uninstallLocation   ; location of uninstall program found in registry
  Var RegVal_uninstallVersion    ; Version / level of uninstaller program.  This only exists at 410 or greater
  Var RegVal_uninstallBitness    ; The uninstaller is 32 or 64 bit.  This only exists at 420 or greater.
  Var RegVal_rexxAssociation     ; File association string for rexx.exe     (.ext / ftype - i.e. .rex RexxScript)
  Var RegVal_rexxEditor          ; ... and editor file name
  Var RegVal_rexxHideAssociation ; File association string for rexxhide.exe (.ext / ftype - i.e. .rexg RexxHide)
  Var RegVal_rexxPawsAssociation ; File association string for rexxpaws.exe (.ext / ftype - i.e. .rexp RexxPaws)
  Var RegVal_sendTo_rexx         ; Add / don't add Send To Rexx item
  Var RegVal_sendTo_rexxHide     ; Add / don't add Send To rexxpaws item
  Var RegVal_sendTo_rexxPaws     ; Add / don't add Send To rexxhide item
  Var RegVal_desktop_icon        ; Create / don't create a Desktop icon

  Var AssociationProgramName     ; Executable being associated  (i.e rexxpaws.exe, rexx.exe, etc..)
  Var AssociationText            ; Descriptive text that goes in registry  (i.e. ooRexx Rexx GUI Program)
  Var AssociationEditor          ; File path name of editor that goes in registry  (i.e. C:\Windows\system32\NotePad.exe)

  Var PreviousVersionInstalled   ; A previous version is installed                   true / false
  Var DoUpgrade                  ; try to do an upgrade install                      true / false
  Var DoUpgradeQuick             ; don't show options pages with diasabled controls  true / false
  Var UpgradeTypeAvailable       ; Level of uninstaller sufficient for upgrade type  true / false

  Var KeyFileName                ; Used to contruct full path to key files.
  Var CheckRxApiLock             ; Used to skipping checking if rxapi is locked.
  Var UserRequestAbort           ; General purpose, set to true if User replies Ok, wanting to abort.

  ; Dialog variables
  Var Dialog
  Var Label_One
  Var Label_Two

  Var Uninstall_Previous_CK
  Var Force_Install_CK

  Var Do_Upgrade_Type_CK
  Var Do_Upgrade_Type_CK_state
  Var Do_Upgrade_Quick_CK
  Var Do_Upgrade_Quick_CK_state

  Var StopRxAPI_CK
  Var StopRxAPI_CK_State

  Var Use_File_Associations_CK
  Var Use_File_Associations_CK_state

  Var SendTo_rexx_CK
  Var SendTo_rexx_CK_state
  Var SendTo_rexxHide_CK
  Var SendTo_rexxHide_CK_state
  Var SendTo_rexxPaws_CK
  Var SendTo_rexxPaws_CK_state

  ; rexx.exe file associations page controls
  Var Rexx_editor_EDIT
  Var Rexx_editor_text
  Var Rexx_editor_PB
  Var Associate_rexx_CK
  Var Associate_rexx_CK_state
  Var Rexx_ext_EDIT
  Var Rexx_ext_text
  Var Rexx_ftype_EDIT
  Var Rexx_ftype_text

  ; rexxhide.exe file associations
  Var Associate_rexxhide_CK
  Var Associate_rexxhide_CK_state
  Var RexxHide_ext_EDIT
  Var RexxHide_ext_text
  Var RexxHide_ftype_EDIT
  Var RexxHide_ftype_text

  ; rexxpaws.exe file associations
  Var Associate_rexxpaws_CK
  Var Associate_rexxpaws_CK_state
  Var RexxPaws_ext_EDIT
  Var RexxPaws_ext_text
  Var RexxPaws_ftype_EDIT
  Var RexxPaws_ftype_text
;--------------------------------
;Include Modern UI

  !include "MUI2.nsh"
  !include "InstallOptions.nsh"
  !include "Library.nsh"
  !include "LogicLib.nsh"
  !include "FileFunc.nsh"
  !include "WordFunc.nsh"
  !include "StrFunc.nsh"
  !include "x64.nsh"


  ;Default installation folder
  InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"

;--------------------------------
;General

  ;Name and file
  Name "@CPACK_NSIS_PACKAGE_NAME@"
  OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"

  ;Set compression
  SetCompressor @CPACK_NSIS_COMPRESSOR@

  ;Require administrator access
  RequestExecutionLevel admin

@CPACK_NSIS_DEFINES@

  !include Sections.nsh

;--- Component support macros: ---
; The code for the add/remove functionality is from:
;   http://nsis.sourceforge.net/Add/Remove_Functionality
; It has been modified slightly and extended to provide
; inter-component dependencies.
Var AR_SecFlags
Var AR_RegFlags
@CPACK_NSIS_SECTION_SELECTED_VARS@

# Create a shortcut using the information provided from CMake.  This versions simplifies
# the process of escaping all of the special characters in CMake
!macro ConfigureShortCut Name Program Arg Icon Icon_index
  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${Name}.lnk" "$INSTDIR\${Program}" '"${Arg}"' "$INSTDIR\${Icon}" ${Icon_index}
!macroend

# Create a shortcut for running a Rexx program using the information provided from CMake.  This versions simplifies
# the process of escaping all of the special characters in CMake
!macro ConfigureRexxShortCut Name Launcher RexxProgram
  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${Name}.lnk" "$INSTDIR\${Launcher}.exe" '"${RexxProgram}"' "$INSTDIR\{Launcher}.exe"
!macroend

# Create a shortcut for a documentation file (all come from the same directory)
!macro ConfigureDocShortCut Name File
  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Docuentation\${Name}.lnk" "$INSTDIR\doc\${File}" "" "$INSTDIR\doc\${File}" 0
!macroend

# The reverse of CreateShortCut.  This removes a short cut for a component.
# the process of escaping all of the special characters in CMake
!macro RemoveShortCut Name
  Delete "$SMPROGRAMS\$MUI_TEMP\${Name}.lnk"
!macroend


; Loads the "selected" flag for the section named SecName into the
; variable VarName.
!macro LoadSectionSelectedIntoVar SecName VarName
 SectionGetFlags ${${SecName}} $${VarName}
 IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits
!macroend

; Loads the value of a variable... can we get around this?
!macro LoadVar VarName
  IntOp $R0 0 + $${VarName}
!macroend

; Sets the value of a variable
!macro StoreVar VarName IntValue
  IntOp $${VarName} 0 + ${IntValue}
!macroend

!macro InstallComponentShortCuts SecName
  ; This macro installs the short cuts associated with a given component.
  ; It relies on macros that are generated by the CMake build

  ; Just pass on to the creation macro
    !insertmacro "Create_ShortCuts_${${SecName}}"
!macroend

!macro RemoveComponentShortCuts SecName
  ; This macro installs the short cuts associated with a given component.
  ; It relies on macros that are generated by the CMake build

  ; Just pass on to the creation macro
    !insertmacro "Remove_ShortCuts_${${SecName}}"
!macroend

;--- Add/Remove callback functions: ---
!macro SectionList MacroName
  ;This macro used to perform operation on multiple sections.
  ;List all of your components in following manner here.
@CPACK_NSIS_COMPONENT_SECTION_LIST@
!macroend

!macro InitSection SecName
  ;  This macro reads component installed flag from the registry and
  ;changes checked state of the section on the components page.
  ;Input: section index constant name specified in Section command.

  ClearErrors
  ;Reading component status from registry
  ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed"
  IfErrors "default_${SecName}"
    ;Status will stay default if registry value not found
    ;(component was never installed)
  IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits
  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags
  IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off
  IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit

  ; Note whether this component was installed before
  !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags
  IntOp $R0 $AR_RegFlags & $AR_RegFlags

  ;Writing modified flags
  SectionSetFlags ${${SecName}} $AR_SecFlags

 "default_${SecName}:"
 !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
!macroend

!macro FinishSection SecName
  ;  This macro reads section flag set by user and removes the section
  ;if it is not selected.
  ;Then it writes component installed flag to registry
  ;Input: section index constant name specified in Section command.

  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags
  ;Checking lowest bit:
  IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
  IntCmp $AR_SecFlags 1 "leave_${SecName}"
    ;Section is not selected:
    ;Calling Section uninstall macro and writing zero installed flag
    !insertmacro "Remove_${${SecName}}"
    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
  "Installed" 0
    Goto "exit_${SecName}"

 "leave_${SecName}:"
    ;Section is selected:
    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
  "Installed" 1

 "exit_${SecName}:"
!macroend

!macro RemoveSection_CPack SecName
  ;  This macro is used to call section's Remove_... macro
  ;from the uninstaller.
  ;Input: section index constant name specified in Section command.

  !insertmacro "Remove_${${SecName}}"
!macroend

; Determine whether the selection of SecName changed
!macro MaybeSelectionChanged SecName
  !insertmacro LoadVar ${SecName}_selected
  SectionGetFlags ${${SecName}} $R1
  IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits

  ; See if the status has changed:
  IntCmp $R0 $R1 "${SecName}_unchanged"
  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected

  IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected"
  !insertmacro "Deselect_required_by_${SecName}"
  goto "${SecName}_unchanged"

  "${SecName}_was_selected:"
  !insertmacro "Select_${SecName}_depends"

  "${SecName}_unchanged:"
!macroend
;--- End of Add/Remove macros ---

;--------------------------------
;Interface Settings

  !define MUI_HEADERIMAGE
  !define MUI_ABORTWARNING

;--------------------------------
; Embedded local includes to get around NSIS include path problems

;  !include "admin.nsh"

; Author: Lilla (lilla@earthlink.net) 2003-06-13
; function IsUserAdmin uses plugin \NSIS\PlusgIns\UserInfo.dll
; This function is based upon code in \NSIS\Contrib\UserInfo\UserInfo.nsi
; This function was tested under NSIS 2 beta 4 (latest CVS as of this writing).
;
; Usage:
;   Call IsUserAdmin
;   Pop $R0   ; at this point $R0 is "true" or "false"
;
Function IsUserAdmin
Push $R0
Push $R1
Push $R2

ClearErrors
UserInfo::GetName
IfErrors Win9x
Pop $R1
UserInfo::GetAccountType
Pop $R2

StrCmp $R2 "Admin" 0 Continue
; Observation: I get here when running Win98SE. (Lilla)
; The functions UserInfo.dll looks for are there on Win98 too,
; but just don't work. So UserInfo.dll, knowing that admin isn't required
; on Win98, returns admin anyway. (per kichik)
; MessageBox MB_OK 'User "$R1" is in the Administrators group'
StrCpy $R0 "true"
Goto Done

Continue:
; You should still check for an empty string because the functions
; UserInfo.dll looks for may not be present on Windows 95. (per kichik)
StrCmp $R2 "" Win9x
StrCpy $R0 "false"
;MessageBox MB_OK 'User "$R1" is in the "$R2" group'
Goto Done

Win9x:
; comment/message below is by UserInfo.nsi author:
; This one means you don't need to care about admin or
; not admin because Windows 9x doesn't either
;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!"
StrCpy $R0 "true"

Done:
;MessageBox MB_OK 'User= "$R1"  AccountType= "$R2"  IsUserAdmin= "$R0"'

Pop $R2
Pop $R1
Exch $R0
FunctionEnd


; function un.IsUserAdmin uses plugin \NSIS\PlusgIns\UserInfo.dll
; This function is based upon code in \NSIS\Contrib\UserInfo\UserInfo.nsi
; This function was tested under NSIS 2 beta 4 (latest CVS as of this writing).
;
; Usage:
;   Call un.IsUserAdmin
;   Pop $R0   ; at this point $R0 is "true" or "false"
;
Function un.IsUserAdmin
Push $R0
Push $R1
Push $R2

ClearErrors
UserInfo::GetName
IfErrors Win9x
Pop $R1
UserInfo::GetAccountType
Pop $R2

StrCmp $R2 "Admin" 0 Continue
; Observation: I get here when running Win98SE. (Lilla)
; The functions UserInfo.dll looks for are there on Win98 too,
; but just don't work. So UserInfo.dll, knowing that admin isn't required
; on Win98, returns admin anyway. (per kichik)
; MessageBox MB_OK 'User "$R1" is in the Administrators group'
StrCpy $R0 "true"
Goto Done

Continue:
; You should still check for an empty string because the functions
; UserInfo.dll looks for may not be present on Windows 95. (per kichik)
StrCmp $R2 "" Win9x
StrCpy $R0 "false"
;MessageBox MB_OK 'User "$R1" is in the "$R2" group'
Goto Done

Win9x:
; comment/message below is by UserInfo.nsi author:
; This one means you don't need to care about admin or
; not admin because Windows 9x doesn't either
;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!"
StrCpy $R0 "true"

Done:
;MessageBox MB_OK 'User= "$R1"  AccountType= "$R2"  IsUserAdmin= "$R0"'

Pop $R2
Pop $R1
Exch $R0
FunctionEnd

;  !include "WriteEnv.nsh"

#
# WriteEnvStr - Writes an environment variable
# Note: Win9x systems requires reboot
#
# Example:
#  Push "HOMEDIR"           # name
#  Push "C:\New Home Dir\"  # value
#  Push "true"              # true or false if admin user
#  Call WriteEnvStr
#
Function WriteEnvStr
  Pop $8 ; $8 IsAdminUser: true or false
  Exch $1 ; $1 has environment variable value
  Exch
  Exch $0 ; $0 has environment variable name
  Push $2

  Call IsNT
  Pop $2
  StrCmp $2 1 WriteEnvStr_NT
    ; Not on NT
    StrCpy $2 $WINDIR 2 ; Copy drive of windows (c:)
    FileOpen $2 "$2\autoexec.bat" a
    FileSeek $2 0 END
    FileWrite $2 "$\r$\nSET $0=$1$\r$\n"
    FileClose $2
    SetRebootFlag true
    Goto WriteEnvStr_done

  WriteEnvStr_NT:
      StrCmp $8 "false" WriteEnvStr_NormalUser
      WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" $0 $1
      DetailPrint "Setting environment variable $0 to $1 for All Users"
      Goto WriteEnvStr_cont
    WriteEnvStr_NormalUser:
      WriteRegStr HKCU "Environment" $0 $1
      DetailPrint "Setting environment variable $0 to $1 for Current User"
    WriteEnvStr_cont:
      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} \
        0 "STR:Environment" /TIMEOUT=5000

  WriteEnvStr_done:
    Pop $2
    Pop $1
    Pop $0
FunctionEnd

#
# un.DeleteEnvStr - Removes an environment variable
# Note: Win9x systems requires reboot
#
# Example:
#  Push "HOMEDIR"           # name
#  Push "true"              # true or false if admin user
#  Call un.DeleteEnvStr
#
Function un.DeleteEnvStr
  Pop $8 ; $8 IsAdminUser: true or false
  Exch $0 ; $0 now has the name of the variable
  Push $1
  Push $2
  Push $3
  Push $4
  Push $5

  Call un.IsNT
  Pop $1
  StrCmp $1 1 DeleteEnvStr_NT
    ; Not on NT
    StrCpy $1 $WINDIR 2
    FileOpen $1 "$1\autoexec.bat" r
    GetTempFileName $4
    FileOpen $2 $4 w
    StrCpy $0 "SET $0="
    SetRebootFlag true

    DeleteEnvStr_dosLoop:
      FileRead $1 $3
      StrLen $5 $0
      StrCpy $5 $3 $5
      StrCmp $5 $0 DeleteEnvStr_dosLoop
      StrCmp $5 "" DeleteEnvStr_dosLoopEnd
      FileWrite $2 $3
      Goto DeleteEnvStr_dosLoop

    DeleteEnvStr_dosLoopEnd:
      FileClose $2
      FileClose $1
      StrCpy $1 $WINDIR 2
      Delete "$1\autoexec.bat"
      CopyFiles /SILENT $4 "$1\autoexec.bat"
      Delete $4
      Goto DeleteEnvStr_done

  DeleteEnvStr_NT:
      StrCmp $8 "false" DeleteEnvStr_NormalUser
      DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" $0
      DetailPrint "Deleting environment variable $0 for All Users"
      Goto DeleteEnvStr_cont
    DeleteEnvStr_NormalUser:
      DeleteRegValue HKCU "Environment" $0
      DetailPrint "Deleting environment variable $0 for Current User"
    DeleteEnvStr_cont:
    SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} \
      0 "STR:Environment" /TIMEOUT=5000

  DeleteEnvStr_done:
    Pop $5
    Pop $4
    Pop $3
    Pop $2
    Pop $1
    Pop $0
FunctionEnd

;--------------------------------
; path functions

!verbose 3
!include "WinMessages.NSH"

;----------------------------------------
; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02"
;----------------------------------------
!verbose 3
!include "WinMessages.NSH"
;====================================================
; get_NT_environment
;     Returns: the selected environment
;     Output : head of the stack
;====================================================
!macro select_NT_profile UN
Function ${UN}select_NT_profile
   StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single
      DetailPrint "Selected environment for all users"
      Push "all"
      Return
   environment_single:
      DetailPrint "Selected environment for current user only."
      Push "current"
      Return
FunctionEnd
!macroend
!insertmacro select_NT_profile ""
!insertmacro select_NT_profile "un."
;----------------------------------------------------
!define NT_current_env 'HKCU "Environment"'
!define NT_all_env     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'

!ifndef WriteEnvStr_RegKey
  !ifdef ALL_USERS
    !define WriteEnvStr_RegKey \
       'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
  !else
    !define WriteEnvStr_RegKey 'HKCU "Environment"'
  !endif
!endif

; AddToPath - Adds the given dir to the search path.
;        Input - head of the stack
;        Note - Win9x systems requires reboot

Function AddToPath
  Exch $0
  Push $1
  Push $2
  Push $3

  # don't add if the path doesn't exist
  IfFileExists "$0\*.*" "" AddToPath_done

  ReadEnvStr $1 PATH
  ; if the path is too long for a NSIS variable NSIS will return a 0
  ; length string.  If we find that, then warn and skip any path
  ; modification as it will trash the existing path.
  StrLen $2 $1
  IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done
    CheckPathLength_ShowPathWarning:
    Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!"
    Goto AddToPath_done
  CheckPathLength_Done:
  Push "$1;"
  Push "$0;"
  Call StrStr
  Pop $2
  StrCmp $2 "" "" AddToPath_done
  Push "$1;"
  Push "$0\;"
  Call StrStr
  Pop $2
  StrCmp $2 "" "" AddToPath_done
  GetFullPathName /SHORT $3 $0
  Push "$1;"
  Push "$3;"
  Call StrStr
  Pop $2
  StrCmp $2 "" "" AddToPath_done
  Push "$1;"
  Push "$3\;"
  Call StrStr
  Pop $2
  StrCmp $2 "" "" AddToPath_done

  StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey
    ReadRegStr $1 ${NT_current_env} "PATH"
    Goto DoTrim
  ReadAllKey:
    ReadRegStr $1 ${NT_all_env} "PATH"
  DoTrim:
  StrCmp $1 "" AddToPath_NTdoIt
    Push $1
    Call Trim
    Pop $1
    StrCpy $0 "$1;$0"
  AddToPath_NTdoIt:
    StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey
      WriteRegExpandStr ${NT_current_env} "PATH" $0
      Goto DoSend
    WriteAllKey:
      WriteRegExpandStr ${NT_all_env} "PATH" $0
    DoSend:
    SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000

    Pop $3
    Pop $2
    Pop $1
    Pop $0
FunctionEnd


; RemoveFromPath - Remove a given dir from the path
;     Input: head of the stack

Function un.RemoveFromPath
  Exch $0
  Push $1
  Push $2
  Push $3
  Push $4
  Push $5
  Push $6

  IntFmt $6 "%c" 26 # DOS EOF

  StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey
    ReadRegStr $1 ${NT_current_env} "PATH"
    Goto unDoTrim
  unReadAllKey:
    ReadRegStr $1 ${NT_all_env} "PATH"
  unDoTrim:
  StrCpy $5 $1 1 -1 # copy last char
  StrCmp $5 ";" +2 # if last char != ;
    StrCpy $1 "$1;" # append ;
  Push $1
  Push "$0;"
  Call un.StrStr ; Find `$0;` in $1
  Pop $2 ; pos of our dir
  StrCmp $2 "" unRemoveFromPath_done
    ; else, it is in path
    # $0 - path to add
    # $1 - path var
    StrLen $3 "$0;"
    StrLen $4 $2
    StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
    StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
    StrCpy $3 $5$6

    StrCpy $5 $3 1 -1 # copy last char
    StrCmp $5 ";" 0 +2 # if last char == ;
      StrCpy $3 $3 -1 # remove last char

    StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey
      WriteRegExpandStr ${NT_current_env} "PATH" $3
      Goto unDoSend
    unWriteAllKey:
      WriteRegExpandStr ${NT_all_env} "PATH" $3
    unDoSend:
    SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000

    Pop $6
    Pop $5
    Pop $4
    Pop $3
    Pop $2
    Pop $1
    Pop $0
FunctionEnd

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Uninstall sutff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

###########################################
#            Utility Functions            #
###########################################

; StrStr
; input, top of stack = string to search for
;        top of stack-1 = string to search in
; output, top of stack (replaces with the portion of the string remaining)
; modifies no other variables.
;
; Usage:
;   Push "this is a long ass string"
;   Push "ass"
;   Call StrStr
;   Pop $R0
;  ($R0 at this point is "ass string")

!macro StrStr un
Function ${un}StrStr
Exch $R1 ; st=haystack,old$R1, $R1=needle
  Exch    ; st=old$R1,haystack
  Exch $R2 ; st=old$R1,old$R2, $R2=haystack
  Push $R3
  Push $R4
  Push $R5
  StrLen $R3 $R1
  StrCpy $R4 0
  ; $R1=needle
  ; $R2=haystack
  ; $R3=len(needle)
  ; $R4=cnt
  ; $R5=tmp
  loop:
    StrCpy $R5 $R2 $R3 $R4
    StrCmp $R5 $R1 done
    StrCmp $R5 "" done
    IntOp $R4 $R4 + 1
    Goto loop
done:
  StrCpy $R1 $R2 "" $R4
  Pop $R5
  Pop $R4
  Pop $R3
  Pop $R2
  Exch $R1
FunctionEnd
!macroend
!insertmacro StrStr ""
!insertmacro StrStr "un."

Function Trim ; Added by Pelaca
	Exch $R1
	Push $R2
Loop:
	StrCpy $R2 "$R1" 1 -1
	StrCmp "$R2" " " RTrim
	StrCmp "$R2" "$\n" RTrim
	StrCmp "$R2" "$\r" RTrim
	StrCmp "$R2" ";" RTrim
	GoTo Done
RTrim:
	StrCpy $R1 "$R1" -1
	Goto Loop
Done:
	Pop $R2
	Exch $R1
FunctionEnd

Function ConditionalAddToRegisty
  Pop $0
  Pop $1
  StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
    WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \
    "$1" "$0"
    ;MessageBox MB_OK "Set Registry: '$1' to '$0'"
    DetailPrint "Set install registry entry: '$1' to '$0'"
  ConditionalAddToRegisty_EmptyString:
FunctionEnd

;--------------------------------

!ifdef CPACK_USES_DOWNLOAD
Function DownloadFile
    IfFileExists $INSTDIR\* +2
    CreateDirectory $INSTDIR
    Pop $0

    ; Skip if already downloaded
    IfFileExists $INSTDIR\$0 0 +2
    Return

    StrCpy $1 "@CPACK_DOWNLOAD_SITE@"

  try_again:
    NSISdl::download "$1/$0" "$INSTDIR\$0"

    Pop $1
    StrCmp $1 "success" success
    StrCmp $1 "Cancelled" cancel
    MessageBox MB_OK "Download failed: $1"
  cancel:
    Return
  success:
FunctionEnd
!endif

;--------------------------------
; Installation types
@CPACK_NSIS_INSTALLATION_TYPES@

;--------------------------------
; Component sections
@CPACK_NSIS_COMPONENT_SECTIONS@

;--------------------------------
; Macros for creating shortcuts for each component
@CPACK_NSIS_COMPONENT_SECTION_SHORTCUTS@

;--------------------------------
; Define some macro setting for the gui
@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
@CPACK_NSIS_INSTALLER_ICON_CODE@
@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@
@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@

;--------------------------------
;Pages
  !insertmacro MUI_PAGE_WELCOME

  !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
  Page custom InstallOptionsPage
  !insertmacro MUI_PAGE_DIRECTORY

  Page custom File_Associations_page File_Associations_leave
  Page custom SendTo_Items_page SendTo_Items_leave
  Page custom Associate_rexx_page Associate_rexx_leave
  Page custom Associate_otherExes_page Associate_otherExes_leave
  Page custom Confirm_page

  ;Start Menu Folder Page Configuration
  !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
  !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER

  @CPACK_NSIS_PAGE_COMPONENTS@

  !insertmacro MUI_PAGE_INSTFILES
  !insertmacro MUI_PAGE_FINISH

  !insertmacro MUI_UNPAGE_CONFIRM
  !insertmacro MUI_UNPAGE_INSTFILES

;--------------------------------
;Languages

  !insertmacro MUI_LANGUAGE "English" ;first language is the default language
  !insertmacro MUI_LANGUAGE "Albanian"
  !insertmacro MUI_LANGUAGE "Arabic"
  !insertmacro MUI_LANGUAGE "Basque"
  !insertmacro MUI_LANGUAGE "Belarusian"
  !insertmacro MUI_LANGUAGE "Bosnian"
  !insertmacro MUI_LANGUAGE "Breton"
  !insertmacro MUI_LANGUAGE "Bulgarian"
  !insertmacro MUI_LANGUAGE "Croatian"
  !insertmacro MUI_LANGUAGE "Czech"
  !insertmacro MUI_LANGUAGE "Danish"
  !insertmacro MUI_LANGUAGE "Dutch"
  !insertmacro MUI_LANGUAGE "Estonian"
  !insertmacro MUI_LANGUAGE "Farsi"
  !insertmacro MUI_LANGUAGE "Finnish"
  !insertmacro MUI_LANGUAGE "French"
  !insertmacro MUI_LANGUAGE "German"
  !insertmacro MUI_LANGUAGE "Greek"
  !insertmacro MUI_LANGUAGE "Hebrew"
  !insertmacro MUI_LANGUAGE "Hungarian"
  !insertmacro MUI_LANGUAGE "Icelandic"
  !insertmacro MUI_LANGUAGE "Indonesian"
  !insertmacro MUI_LANGUAGE "Irish"
  !insertmacro MUI_LANGUAGE "Italian"
  !insertmacro MUI_LANGUAGE "Japanese"
  !insertmacro MUI_LANGUAGE "Korean"
  !insertmacro MUI_LANGUAGE "Kurdish"
  !insertmacro MUI_LANGUAGE "Latvian"
  !insertmacro MUI_LANGUAGE "Lithuanian"
  !insertmacro MUI_LANGUAGE "Luxembourgish"
  !insertmacro MUI_LANGUAGE "Macedonian"
  !insertmacro MUI_LANGUAGE "Malay"
  !insertmacro MUI_LANGUAGE "Mongolian"
  !insertmacro MUI_LANGUAGE "Norwegian"
  !insertmacro MUI_LANGUAGE "Polish"
  !insertmacro MUI_LANGUAGE "Portuguese"
  !insertmacro MUI_LANGUAGE "PortugueseBR"
  !insertmacro MUI_LANGUAGE "Romanian"
  !insertmacro MUI_LANGUAGE "Russian"
  !insertmacro MUI_LANGUAGE "Serbian"
  !insertmacro MUI_LANGUAGE "SerbianLatin"
  !insertmacro MUI_LANGUAGE "SimpChinese"
  !insertmacro MUI_LANGUAGE "Slovak"
  !insertmacro MUI_LANGUAGE "Slovenian"
  !insertmacro MUI_LANGUAGE "Spanish"
  !insertmacro MUI_LANGUAGE "Swedish"
  !insertmacro MUI_LANGUAGE "Thai"
  !insertmacro MUI_LANGUAGE "TradChinese"
  !insertmacro MUI_LANGUAGE "Turkish"
  !insertmacro MUI_LANGUAGE "Ukrainian"
  !insertmacro MUI_LANGUAGE "Welsh"


;--------------------------------
;Reserve Files

  ;These files should be inserted before other files in the data block
  ;Keep these lines before any File command
  ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)

  ReserveFile "NSIS.InstallOptions.ini"
; Updated for MUI2
;  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
;  ReserveFile '${NSISDIR}\Plugins\InstallOptions.dll'

;--------------------------------
;Installer Sections

Section "-Core installation"
  ;Use the entire tree produced by the INSTALL target.  Keep the
  ;list of directories here in sync with the RMDir commands below.
  SetOutPath "$INSTDIR"
  @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
  @CPACK_NSIS_FULL_INSTALL@

  ;Store installation folder
  WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR

  ;Create uninstaller
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  Push "DisplayName"
  Push "@CPACK_NSIS_DISPLAY_NAME@"
  Call ConditionalAddToRegisty
  Push "DisplayVersion"
  Push "@CPACK_PACKAGE_VERSION@"
  Call ConditionalAddToRegisty
  Push "Publisher"
  Push "@CPACK_PACKAGE_VENDOR@"
  Call ConditionalAddToRegisty
  Push "UninstallString"
  Push "$INSTDIR\Uninstall.exe"
  Call ConditionalAddToRegisty
  Push "NoRepair"
  Push "1"
  Call ConditionalAddToRegisty

  !ifdef CPACK_NSIS_ADD_REMOVE
  ;Create add/remove functionality
  Push "ModifyPath"
  Push "$INSTDIR\AddRemove.exe"
  Call ConditionalAddToRegisty
  !else
  Push "NoModify"
  Push "1"
  Call ConditionalAddToRegisty
  !endif

  ; Optional registration
  Push "DisplayIcon"
  Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
  Call ConditionalAddToRegisty
  Push "HelpLink"
  Push "@CPACK_NSIS_HELP_LINK@"
  Call ConditionalAddToRegisty
  Push "URLInfoAbout"
  Push "@CPACK_NSIS_URL_INFO_ABOUT@"
  Call ConditionalAddToRegisty
  Push "Contact"
  Push "@CPACK_NSIS_CONTACT@"
  Call ConditionalAddToRegisty
  !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State"
  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application

  ;Create shortcuts
  CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
@CPACK_NSIS_CREATE_ICONS@
@CPACK_NSIS_CREATE_ICONS_EXTRA@
  ; additional shortcuts defined in CMake
  !insertmacro SectionList "InstallComponentShortCuts"

  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"

  ;Read a value from an InstallOptions INI file
  !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State"
  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State"
  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State"

  ; Write special uninstall registry entries
  Push "StartMenu"
  Push "$STARTMENU_FOLDER"
  Call ConditionalAddToRegisty
  Push "DoNotAddToPath"
  Push "$DO_NOT_ADD_TO_PATH"
  Call ConditionalAddToRegisty
  Push "AddToPathAllUsers"
  Push "$ADD_TO_PATH_ALL_USERS"
  Call ConditionalAddToRegisty
  Push "AddToPathCurrentUser"
  Push "$ADD_TO_PATH_CURRENT_USER"
  Call ConditionalAddToRegisty
  Push "InstallToDesktop"
  Push "$INSTALL_DESKTOP"
  Call ConditionalAddToRegisty

  !insertmacro MUI_STARTMENU_WRITE_END

@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@

SectionEnd

Section "-Add to path"
  Push $INSTDIR\bin
  StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
  StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
    Call AddToPath
  doNotAddToPath:
SectionEnd

;--------------------------------
; Create custom pages
Function InstallOptionsPage
  !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@"
  !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini"

FunctionEnd

;--------------------------------
; determine admin versus local install
Function un.onInit

  ClearErrors
  UserInfo::GetName
  IfErrors noLM
  Pop $0
  UserInfo::GetAccountType
  Pop $1
  StrCmp $1 "Admin" 0 +3
    SetShellVarContext all
    ;MessageBox MB_OK 'User "$0" is in the Admin group'
    Goto done
  StrCmp $1 "Power" 0 +3
    SetShellVarContext all
    ;MessageBox MB_OK 'User "$0" is in the Power Users group'
    Goto done

  noLM:
    ;Get installation folder from registry if available

  done:

FunctionEnd


Section -FinishComponents
  ;Removes unselected components and writes component status to registry
  !insertmacro SectionList "FinishSection"

!ifdef CPACK_NSIS_ADD_REMOVE
  ; Get the name of the installer executable
  System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'
  StrCpy $R3 $R0

  ; Strip off the last 13 characters, to see if we have AddRemove.exe
  StrLen $R1 $R0
  IntOp $R1 $R0 - 13
  StrCpy $R2 $R0 13 $R1
  StrCmp $R2 "AddRemove.exe" addremove_installed

  ; We're not running AddRemove.exe, so install it
  CopyFiles $R3 $INSTDIR\AddRemove.exe

  addremove_installed:
!endif
SectionEnd
;--- End of Add/Remove callback functions ---

;--------------------------------
; Component dependencies
Function .onSelChange
  !insertmacro SectionList MaybeSelectionChanged
FunctionEnd

;--------------------------------
;Uninstaller Section

Section "Uninstall"
  ReadRegStr $START_MENU SHCTX \
   "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu"
  ;MessageBox MB_OK "Start menu is in: $START_MENU"
  ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \
    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath"
  ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \
    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers"
  ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \
    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser"
  ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
  ReadRegStr $INSTALL_DESKTOP SHCTX \
    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop"
  ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "

@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@

  ;Remove files we installed.
  ;Keep the list of directories here in sync with the File commands above.
@CPACK_NSIS_DELETE_FILES@
@CPACK_NSIS_DELETE_DIRECTORIES@

!ifdef CPACK_NSIS_ADD_REMOVE
  ;Remove the add/remove program
  Delete "$INSTDIR\AddRemove.exe"
!endif

  ;Remove the uninstaller itself.
  Delete "$INSTDIR\Uninstall.exe"
  DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"

  ;Remove the installation directory if it is empty.
  RMDir "$INSTDIR"

  ; Remove the registry entries.
  DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"

  ; Removes all optional components
  !insertmacro SectionList "RemoveSection_CPack"

  !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP

  Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
  ; Additional shortcuts defined with CMake
  !insertmacro SectionList "RemoveComponentShortCuts"

@CPACK_NSIS_DELETE_ICONS@
@CPACK_NSIS_DELETE_ICONS_EXTRA@

  ;Delete empty start menu parent directories
  StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"

  startMenuDeleteLoop:
    ClearErrors
    RMDir $MUI_TEMP
    GetFullPathName $MUI_TEMP "$MUI_TEMP\.."

    IfErrors startMenuDeleteLoopDone

    StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop
  startMenuDeleteLoopDone:

  ; If the user changed the shortcut, then untinstall may not work. This should
  ; try to fix it.
  StrCpy $MUI_TEMP "$START_MENU"
  Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
@CPACK_NSIS_DELETE_ICONS_EXTRA@

  ;Delete empty start menu parent diretories
  StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"

  secondStartMenuDeleteLoop:
    ClearErrors
    RMDir $MUI_TEMP
    GetFullPathName $MUI_TEMP "$MUI_TEMP\.."

    IfErrors secondStartMenuDeleteLoopDone

    StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop
  secondStartMenuDeleteLoopDone:

  DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"

  Push $INSTDIR\bin
  StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
    Call un.RemoveFromPath
  doNotRemoveFromPath:
SectionEnd

;--------------------------------
; determine admin versus local install
; Is install for "AllUsers" or "JustMe"?
; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
; This function is used for the very first "custom page" of the installer.
; This custom page does not show up visibly, but it executes prior to the
; first visible page and sets up $INSTDIR properly...
; Choose different default installation folder based on SV_ALLUSERS...
; "Program Files" for AllUsers, "My Documents" for JustMe...

Function .onInit
  StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst

  ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString"
  StrCmp $0 "" inst

  MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
  "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \
  IDYES uninst IDNO inst
  Abort

;Run the uninstaller
uninst:
  ClearErrors
  StrLen $2 "\Uninstall.exe"
  StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path
  ExecWait '$0 _?=$3' ;Do not copy the uninstaller to a temp file

  IfErrors uninst_failed inst
uninst_failed:
  MessageBox MB_OK|MB_ICONSTOP "Uninstall failed."
  Abort


inst:
  ; Reads components status for registry
  !insertmacro SectionList "InitSection"

  ; check to see if /D has been used to change
  ; the install directory by comparing it to the
  ; install directory that is expected to be the
  ; default
  StrCpy $IS_DEFAULT_INSTALLDIR 0
  StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2
    StrCpy $IS_DEFAULT_INSTALLDIR 1

  StrCpy $SV_ALLUSERS "JustMe"
  ; if default install dir then change the default
  ; if it is installed for JustMe
  StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
    StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"

  ClearErrors
  UserInfo::GetName
  IfErrors noLM
  Pop $0
  UserInfo::GetAccountType
  Pop $1
  StrCmp $1 "Admin" 0 +4
    SetShellVarContext all
    ;MessageBox MB_OK 'User "$0" is in the Admin group'
    StrCpy $SV_ALLUSERS "AllUsers"
    Goto done
  StrCmp $1 "Power" 0 +4
    SetShellVarContext all
    ;MessageBox MB_OK 'User "$0" is in the Power Users group'
    StrCpy $SV_ALLUSERS "AllUsers"
    Goto done

  noLM:
    StrCpy $SV_ALLUSERS "AllUsers"
    ;Get installation folder from registry if available

  done:
  StrCmp $SV_ALLUSERS "AllUsers" 0 +3
    StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
      StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"

  StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage
    !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini"

  noOptionsPage:
FunctionEnd

/** Associate_rexx_page()  Custom page function.
 *
 * Presents the option to the user of creating a file association for rexx.exe
 *
 * The page is skipped if not using file associations, or if we are doing a
 * quick upgrade.
 */
Function Associate_rexx_page

  ${If} $Use_File_Associations_CK_state == ${BST_UNCHECKED}
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
    !insertmacro MUI_HEADER_TEXT "The file extension for rexx.exe and Rexx program editor choices." \
                                 "These choices can not be changed during an upgrade type of install."
  ${else}
    !insertmacro MUI_HEADER_TEXT "Associate a file extension with rexx.exe." "Pick the editor to be used when the Edit \
                                 item of the context menu is selected."
  ${EndIf}

  nsDialogs::Create 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_OnBack} Associate_rexx_leave

  ${NSD_CreateLabel} 0u 0u 100% 16u \
    "Select the editor to be used with your ooRexx file type(s).  This adds the Edit menu item to \
    the context menu of the file type.  The same editor is used for all file types."

  Pop $Label_One

  ; Editor line
  ${NSD_CreateLabel}     0u 20u 60u  8u "Full path to editor:"
  Pop $0  ; Discarded

  ${NSD_CreateText}      0u 30u 185u 12u $Rexx_editor_text
  Pop $Rexx_editor_EDIT

  ${NSD_CreateButton}   190u 28u  45u 16u "Browse..."
  Pop $Rexx_editor_PB

	System::Call shlwapi::SHAutoComplete(i$Rexx_editor_EDIT, i${SHACF_FILESYSTEM})


  ${NSD_CreateLabel} 0u 60u 100% 24u \
    "By default in ${LONGNAME} installations the Rexx interpreter, rexx.exe, is associated with the \
    ${DefRexxExt} extension using the file type name of ${DefRexxFType}.  However, you can change these values if \
    you care to."

  Pop $Label_Two

  ${NSD_CreateGroupBox} 0u 90u 100% 44u "File Association for rexx.exe"
  Pop $0  ; Discarded

  ${NSD_CreateCheckBox} 8u  104u 80% 8u "Create rexx.exe file association"
  Pop $Associate_rexx_CK

  ${NSD_SetState} $Associate_rexx_CK $Associate_rexx_CK_state

  ; Extension line
  ${NSD_CreateLabel}     16u  116u  75u  8u "Extension (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      91u  114u  36u 12u $Rexx_ext_text
  Pop $Rexx_ext_EDIT

  ; File type line
  ${NSD_CreateLabel}     137u 116u  90u  8u "File type name (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      228u 114u  46u 12u $Rexx_ftype_text
  Pop $Rexx_ftype_EDIT

  ${NSD_SetState} $Associate_rexx_CK $Associate_rexx_CK_state
  ${NSD_SetState} $SendTo_rexx_CK $SendTo_rexx_CK_state

  ${If} $Associate_rexx_CK_state == ${BST_UNCHECKED}
  ${orif} $DoUpgrade == 'true'
	  EnableWindow $Rexx_ext_EDIT 0
	  EnableWindow $Rexx_ftype_EDIT 0

    ${If} $DoUpgrade == 'true'
  	  EnableWindow $Rexx_editor_EDIT 0
  	  EnableWindow $Rexx_editor_PB 0
  	  EnableWindow $Associate_rexx_CK 0
      EnableWindow $Label_One 0
      EnableWindow $Label_Two 0
      Call PageDisableQuit
  	${EndIf}
	${EndIf}

  ${NSD_OnClick} $Associate_rexx_CK EnableRexxAssociation
  ${NSD_OnClick} $Rexx_editor_PB Get_rexx_editor_file

  nsDialogs::Show

FunctionEnd

/** Associate_rexx_leave()  Call back function.
 *
 * This function is called when the Rexx association page is left.  We check
 * that the text fields are 'sane' and return the user to the page if they
 * are not.  If the fields are good, the state of the dialog controls is saved.
 */
Function Associate_rexx_leave

  ${NSD_GetState} $Associate_rexx_CK $Associate_rexx_CK_state

  ${If} $Associate_rexx_CK_state == ${BST_CHECKED}
    ${NSD_GetText} $Rexx_ext_EDIT $0
    ${NSD_GetText} $Rexx_ftype_EDIT $1

    ; If either the extension field or the ftype field are blank, abort.
    ${If} $0 == ""
    ${orif} $1 == ""
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Creating a file association requires that$\n\
        both the file extension and the file type field$\n\
        be filed in."

      ${If} $0 == ""
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

    ; Copy the first char of the ext field to $0 if not a '.', abort.
    StrCpy $2 $0 1
    ${If} $2 != "."
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Please include the leading dot '.' of the file$\n\
        extension."
      SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ext_EDIT 1
      Abort
    ${EndIf}

    ; Check that the user did not include any spaces in either field. If so abort
    push $0
    call CheckForSpaces
    pop $2
    push $1
    call CheckForSpaces
    pop $3

    ${If} $2 > 0
    ${orif} $3 > 0
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Neither the file extension field nor the file$\n\
        type name field can contain a space."

      ${If} $2 > 0
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

  ${EndIf}


  ; Okay text fields are okay.  If editor field is blank, it is just not used.
  ${NSD_GetText} $Rexx_ext_EDIT $Rexx_ext_text
  ${NSD_GetText} $Rexx_ftype_EDIT $Rexx_ftype_text
  ${NSD_GetText} $Rexx_editor_EDIT $Rexx_editor_text

FunctionEnd

/** Uninstall_Old_ooRexx_page()  Custom page function.
 *
 * This page is show when a previously installed version ooRexx is detected.  It
 * explains to the user that it is necessary to uninstall the previous version
 * and forces the user to check a secondary check box to "force" the install to
 * continue without uninstalling the previous version.
 *
 * The intent is to make it difficult to not do the uninstall and ensure that
 * the user knows installing over the top of an existing install is not
 * supported.
 */
Function Uninstall_Old_ooRexx_page

  /* Skip this page if no previous version is present */
  ${If} $PreviousVersionInstalled == "false"
    Abort
  ${EndIf}

  !insertmacro MUI_HEADER_TEXT "Previous ooRexx Version." "A previous version of ${LONGNAME} is already installed."
  nsDialogs::Create /NOUNLOAD 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_CreateLabel} 0 0 100% 40u \
    "A version of ${LONGNAME} is currently installed.  If the previous version is \
    not uninstalled it is almost certain to cause problems.$\n$\n\
    To uninstall the previous version check the check box. To skip the uninstall step, \
    uncheck the check box."
  Pop $Label_One

  ${NSD_CreateCheckBox} 0 44u 100% 8u "Uninstall previous version of ooRexx"
  Pop $Uninstall_Previous_CK
  ${NSD_Check} $Uninstall_Previous_CK
  ${NSD_OnClick} $Uninstall_Previous_CK ShowHideForceInstall

  ${NSD_CreateLabel} 0 70u 100% 48u \
    "There are very few cases where installing ${LONGNAME} without removing the previous \
    version will work.  If you think you know better than this, proceed with the installation. \
    However, the ${SHORTNAME} developers will not support this type of installation$\n$\n\
    To proceed with the install without uninstalling the previous version of ooRexx you must \
    check the Force install to continue check box."
  Pop $Label_Two
  ShowWindow $Label_Two ${SW_HIDE}

  ${NSD_CreateCheckBox} 0 122u 100% 8u "Force install to continue"
  Pop $Force_Install_CK
  ${NSD_Uncheck} $Force_Install_CK
  ShowWindow $Force_Install_CK ${SW_HIDE}

  nsDialogs::Show

FunctionEnd

/** ShowHideForceInstall()  Callback function.
 *
 * Called when the Unistall previous ooRexx version check box is clicked.
 *
 * If the check box is checked, the user wants to uninstall and we hide the
 * force check box.  If the user unchecks the uninstall check box we show the
 * foce check box.
 */
Function ShowHideForceInstall
	Pop $Uninstall_Previous_CK
	${NSD_GetState} $Uninstall_Previous_CK $0

	${If} $0 == 1
		ShowWindow $Label_Two ${SW_HIDE}
		ShowWindow $Force_Install_CK ${SW_HIDE}
	${Else}
		ShowWindow $Label_Two ${SW_SHOW}
		ShowWindow $Force_Install_CK ${SW_SHOW}
    ${NSD_Uncheck} $Force_Install_CK
	${EndIf}
FunctionEnd

/** OpenUninstallLog()
 *
 * Opens up the uninstall log.  In the hidden OpenLogFile section, the $INSTDIR
 * must be created before this function is callled.
 */
Function OpenUninstallLog
  IfFileExists "$INSTDIR\${UninstLog}" +3
    FileOpen $UninstLog "$INSTDIR\${UninstLog}" w
    Goto +4
  SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" a
  FileSeek $UninstLog 0 END
FunctionEnd

/** CloseUninstallLog()
 *
 * Closes up the uninstall log.
 */
Function CloseUninstallLog
  FileClose $UninstLog
  SetFileAttributes "$INSTDIR\${UninstLog}" READONLY|SYSTEM|HIDDEN
FunctionEnd

/** Uninstall_Old_ooRexx_Leave()  Callback function.
 *
 * The installer calls this function when the user presses the Next button on
 * the uninstall old ooRexx version page.
 */
Function Uninstall_Old_ooRexx_Leave
	${NSD_GetState} $Uninstall_Previous_CK $0
	${NSD_GetState} $Force_Install_CK $1

  /* If the user said to not uninstall the previous and did not check force the
   * install, then send them back to the page.
   */
  ${If} $0 == 0
  ${andif} $1 == 0
    MessageBox MB_OK \
      "To bypass uninstalling the previous version of ooRexx you must check$\n\
      the Force install check box.  If it is not the intention to skip the$\n\
      uninstall step, then the Uninstall previous version must be checked.$\n$\n\
      Please check the appropriate check boxes to continue." \
      /SD IDOK
      Abort
  ${EndIf}

  /* If the user said to not uninstall the previous and to force the install,
   * then we skip the uninstall.  To signal this we set the
   * PreviousVersionInstalled variable to false.
   */
  ${If} $0 == 0
  ${andif} $1 == 1
    StrCpy $PreviousVersionInstalled 'false'
  ${EndIf}

FunctionEnd

/** Uninstall_Type_page()  Custom page function.
 *
 * This page is show when a previously installed version ooRexx is detected,
 * and the uninstaller version is capable of doing an upgrade type of install.
 *
 * It gives the user the option of only deleting the installed files while
 * leaving the environment, registry, etc., setting untouched.
 */
Function Uninstall_Type_page

  /* Skip this page if no previous version is present */
  ${If} $PreviousVersionInstalled == "false"
    Abort
  ${EndIf}

  ${If} $UpgradeTypeAvailable == 'false'
    Call Do_The_Uninstall
    Abort
  ${EndIf}

  !insertmacro MUI_HEADER_TEXT "Upgrade Previous ooRexx Version." "It is possible to do an 'upgrade' type of install."
  nsDialogs::Create /NOUNLOAD 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}


  ${NSD_CreateLabel} 0u 0u 100% 64u \
    "An 'upgrade' type of install will remove all the previously installed files and install \
    the new version of ${SHORTNAME}.  However, it will not undo any of the environment, file \
    association, or registry settings done by the previous install.$\n$\n\
    Use this type of install to quickly replace the old version files with the new version \
    files. Or, when you have customized these types of settings and do not wish them changed.$\n$\n\
    Note: with this type of install, the install location and other settings can NOT be changed.$\n$\n\"
  Pop $Label_One

  ${NSD_CreateCheckBox} 0u 68u 100% 8u "Perform an upgrade type of install"
  Pop $Do_Upgrade_Type_CK

  ${NSD_CreateLabel} 0u 92u 100% 24u \
    "A quick upgrade type of install will skip the pages pertaining to options that can not be changed.  \
    Otherwise the option pages are shown so the value of the options can be seen, but it is still not \
    possible to change the values."
  Pop $Label_Two

  ${NSD_CreateCheckBox} 0u 120u 100% 8u "Perform a quick upgrade type of install"
  Pop $Do_Upgrade_Quick_CK

  ${NSD_OnBack} Uninstall_Type_onBack
  ${NSD_OnClick} $Do_Upgrade_Type_CK ShowHideQuickUninstall

	${NSD_SetState} $Do_Upgrade_Type_CK $Do_Upgrade_Type_CK_state
	${NSD_SetState} $Do_Upgrade_Quick_CK $Do_Upgrade_Quick_CK_state

  ${If} $Do_Upgrade_Type_CK_state == ${BST_UNCHECKED}
		ShowWindow $Label_Two ${SW_HIDE}
		ShowWindow $Do_Upgrade_Quick_CK ${SW_HIDE}
  ${EndIf}

  ; Set focus to the page dialog rather than the installer dialog, set focus to
  ; the check box, and then show the page dialog
  SendMessage $Dialog ${WM_SETFOCUS} $HWNDPARENT 0
  SendMessage $Dialog ${WM_NEXTDLGCTL} $Do_Upgrade_Type_CK 1

  nsDialogs::Show

FunctionEnd

/** Uninstall_Type_onBack()  Call back function
 *
 * Invoked when the user clicks the back button on the Uninstall type page.  We
 * save the state of the check boxes on the page.
 */
Function Uninstall_Type_onBack
	${NSD_GetState} $Do_Upgrade_Type_CK $Do_Upgrade_Type_CK_state
	${NSD_GetState} $Do_Upgrade_Quick_CK $Do_Upgrade_Quick_CK_state
FunctionEnd

/** Uninstall_Type_Leave()  Call back function.
 *
 * The installer calls this function when the user presses the Next button on
 * the uninstall type page.  We don't save the check box state because we
 * immediately run the uninstall and the user won't see this page again.
 * Rather, we set the DoUpgrade / DoUpgradeQuick variables to the proper values.
 */
Function Uninstall_Type_Leave
	${NSD_GetState} $Do_Upgrade_Type_CK $Do_Upgrade_Type_CK_state
	${NSD_GetState} $Do_Upgrade_Quick_CK $Do_Upgrade_Quick_CK_state

  ${If} $Do_Upgrade_Type_CK_state == ${BST_CHECKED}
    StrCpy $DoUpgrade 'true'

    ${If} $Do_Upgrade_Quick_CK_state = ${BST_CHECKED}
      StrCpy $DoUpgradeQuick 'true'
    ${else}
      StrCpy $DoUpgradeQuick 'false'
    ${EndIf}
  ${else}
    StrCpy $DoUpgrade 'false'
    StrCpy $DoUpgradeQuick 'false'
  ${EndIf}

  Call Do_The_Uninstall

FunctionEnd

/** ShowHideQuickUninstall() Call back function
 *
 * Invoked when the user clicks the Perform an upgrade type of install check
 * box.  Shows or hides the Perform a quick upgrade type of install check box.
 */
Function ShowHideQuickUninstall
	Pop $Do_Upgrade_Type_CK
	${NSD_GetState} $Do_Upgrade_Type_CK $0

	${If} $0 == ${BST_CHECKED}
		ShowWindow $Label_Two ${SW_SHOW}
		ShowWindow $Do_Upgrade_Quick_CK ${SW_SHOW}
	${else}
		ShowWindow $Label_Two ${SW_HIDE}
		ShowWindow $Do_Upgrade_Quick_CK ${SW_HIDE}
	${EndIf}
FunctionEnd

/** Do_The_Uninstall()
 *
 * Executes the uninstall program and waits for its return.  The user could
 * have:
 *    Finished the uninstall
 *    Canceled the uninstall because they want to stop any running Rexx programs
 *    Canceled the uninstll for some other reason
 *
 * In addition, the script may have aborted the uninstall for some unexplained
 * error.
 *
 * In all cases we quit the install.  We put up a message box to explain why we
 * are quitting in most cases, the only exception is if the user choose to quit
 * to stop any running Rexx programs.
 *
 * @note  If we are doing an upgrade install, then we need to install to the
 *        same location as the original install.  This could easily be different
 *        than what $INSTDIR currently is, so we set $INSTDIR to our uninstall
 *        location.  For an upgrade install, the portion of the installer that
 *        allows the user to pick the install location will be disabled.
 */
Function Do_The_Uninstall

  ; Use $3 for the arg to the uninstall program.
  ${If} $DoUpgrade == 'true'
    StrCpy $INSTDIR $RegVal_uninstallLocation
    StrCpy $3 "upgrade"

    ${If} $DoUpgradeQuick == 'true'
      StrCpy $3 "upgradeQuick"
    ${EndIf}
  ${EndIf}

  HideWindow
  ClearErrors

  /* the "_?=$RegVal_uninstallLocation" portion of the command sets the
   * uninstall dir to $R2 and *prevents* the uninstaller from running in the
   * temp dir, which is what we want.
   */
  ExecWait '$RegVal_uninstallString /U=$3 _?=$RegVal_uninstallLocation' $0

  IfErrors UninstallErrors
  ${If} $0 == 0
    ; No errors, do a sanity check and finish up.
    IfFileExists "$INSTDIR\${KEYFILE1}" UninstallErrors
    IfFileExists "$INSTDIR\${KEYFILE2}" UninstallErrors
    Delete "$RegVal_uninstallLocation\${UNINSTALLER}"
    RMDir "$RegVal_uninstallLocation"

    BringToFront
    Goto NotInstalled
  ${EndIf}

  ${If} $0 == 1
    ; The user canceled the uninstall ...
    MessageBox MB_OK|MB_ICONEXCLAMATION|MB_TOPMOST \
               "You have elected to cancel the uninstall of the previous version of$\n\
               ${SHORTNAME}.  There are very few cases where installing ${LONGNAME}$\n\
               without removing the previous version will work and this installation$\n\
               will abort.$\n$\n\
               If you are determined to install ${SHORTNAME} without removing the$\n\
               previous version, rerun the installation and select to not uninstall$\n\
               the previous version.  Then select to force the installation." \
               /SD IDOK
    Goto DoAbort
  ${EndIf}

  ${If} $0 == 4
    ; The user wants to quit to stop rxapi.  Only set to 4 if the user cancels
    ; on the page where she is asked to stop rxapi.  On that page she is given
    ; the option to quit completely.
    Goto DoAbort
  ${EndIf}

  ${If} $0 == 5
    ; 5 is only set when there are locked files
    MessageBox MB_OK|MB_ICONEXCLAMATION|MB_TOPMOST \
               "The uninstall of the previous version of ${SHORTNAME} was terminated by$\n\
               the uninstall script.  The most likely cause of this is that there are$\n\
               Rexx programs still running, which prevents critical files from being$\n\
               updated.$\n$\n\
               The installation will abort.$\n$\n\
               You must ensure all Rexx programs are ended.  Then restart the installation." \
               /SD IDOK

    Goto DoAbort
  ${EndIf}

  ; Return code is 2 or greater, but not 4 or 5.  2 is uninstall canceled by
  ; script, we treat anything greater than 2 in the same way.
  MessageBox MB_OK|MB_ICONEXCLAMATION|MB_TOPMOST \
             "The uninstall of the previous version of ${SHORTNAME} was terminated by$\n\
             the uninstall script.  The most likely cause of this is that the rxapi$\n\
             process is running, either as a service or stand alone, and could not be$\n\
             stopped.$\n$\n\
             When the previous version of rxapi is not stopped, the new version of$\n\
             of ${SHORTNAME} can not be installed correctly.$\n$\n\
             The installation will abort.$\n$\n\
             You can:$\n$\n\
             1.) Contact the developers on the SourceForge project for help.$\n$\n\
             2.) Try stopping rxapi manually and rerunning the installation.  If$\n\
             rxapi is installed as a service, use the service manager to stop rxapi.$\n\
             Otherwise, use the task manager to stop the rxapi process.$\n$\n\
             3.) Elect to not stop rxapi and to not remove the previous version.  To$\n\
             do this, rerun the installation and click No when asked to uninstall$\n\
             the previous version.  Then click Yes when asked if you want to$\n\
             continue.  However, if you do this ${SHORTNAME} will not be installed$\n\
             correctly." \
             /SD IDOK
  Goto DoAbort

  UninstallErrors:
    MessageBox MB_OK|MB_ICONEXCLAMATION|MB_TOPMOST \
               "There were unexpected errors uninstalling the previous version$\n\
               of ${SHORTNAME}.  There are very few cases where installing ${LONGNAME}$\n\
               without removing the previous version will work and this installation$\n\
               will abort.  You should first try rerunning the installtion.$\n$\n\
               If this is the second attempt at installation and you still get this$\n\
               message, you can:$\n$\n\
               1.) Contact the developers on the SourceForge project for help.$\n$\n\
               2.) Try removing the previous version manually and rerun the installation.$\n$\n\
               3.) Elect to not remove the previous version.  To do this, rerun the installation$\n\
               and click No when asked to uninstall the previous version.  Then click Yes when$\n\
               asked if you want to continue.$\n$\n\
               In all cases, please report this problem to the ${SHORTNAME} project on SourceForge." \
               /SD IDOK
    Goto DoAbort

  DoAbort:
    Quit

  NotInstalled:
  ; The previous version is now uninstalled, so we set the variable to reflect that.
  StrCpy $PreviousVersionInstalled 'false'
FunctionEnd

/** Ok_Stop_RxAPI_page()  Custom page function.
 *
 * This is a custom page that is shown if rxapi is still running.  If rxapi.exe
 * is not running the page is skipped.  On the page, the user is asked for the
 * okay to stop rxapi and advised of possible consequences.  If the user says
 * no, the install will be aborted..
 */
Function Ok_Stop_RxAPI_page
  Call CheckIsRxapiService
  Call CheckIsRxapiRunning

  ${If} $RxapiIsRunning == 'false'
    Abort
  ${EndIf}

  !insertmacro MUI_HEADER_TEXT "The ${LONGNAME} memory manager (rxapi) is currently running." \
                               "A new version of rxapi can not be installed while rxapi is running."
  nsDialogs::Create /NOUNLOAD 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_CreateLabel} 0 0 100% 112u \
    "A previous version of the ${LONGNAME} memory manager (rxapi) is currently running. \
    The new version of rxapi can not be installed while the previous version is running.$\n$\n\
    When the Stop rxapi check box is checked, the installation will stop rxapi before \
    proceeding.  If the check box is not checked, rxapi will not be stopped.$\n$\n\
    If rxapi is not stopped the install will be canceled.$\n$\n\
    If, and only if, there are Rexx programs running, stopping the memory manager could \
    possibly cause data loss.$\n$\n\
    If you are worried about this, please uncheck the Stop rxapi check box.  When the \
    install ends, stop all running Rexx programs, and rerun the installation program."

  Pop $Label_One

  ${NSD_CreateCheckBox} 0 116u 100% 15u "Stop rxapi"
  Pop $StopRxAPI_CK
  ${NSD_SetState} $StopRxAPI_CK 1

  nsDialogs::Show

FunctionEnd

/** Ok_Stop_RxAPI_leave()  Call back function.
 *
 * Invoked when the user leaves the page that asks for permission to stop the
 * rxapi process.  We check if the user said okay or not.  If the user does not
 * say okay we quit the install.
 *
 * When the user does say okay, we stop rxapi and check that it is indeed
 * stopped.  If it is not stopped, we inform the user and also quit the install.
 */
Function Ok_Stop_RxAPI_leave

  ${NSD_GetState} $StopRxAPI_CK $StopRxAPI_CK_State

  ${If} $StopRxAPI_CK_State == 0
    Quit
  ${EndIf}

  Call StopRxapi
  Pop $R0
  ${If} $R0 == 'Ok'
    Goto NotRunning
  ${EndIf}

  ; rxapi was not stopped, the error code is now at top of stack
  Pop $R0

  MessageBox MB_OK|MB_ICONEXCLAMATION|MB_TOPMOST \
             "Can not determine conclusively that the Open Object Rexx memory manager (rxapi) is$\n\
             stopped.  Since a new version of rxapi can not be installed while rxapi is running,$\n\
             the installation will quit.$\n$\n\
             Please use the task manager to locate rxapi.exe and end that process, then restart the$\n\
             installation.  If you are uncomfortable with using the task manager, contact the$\n\
             ${SHORTNAME} developers on SourceForge for help.$\n$\n\
             If you report this problem, please note that the error code is $R0." /SD IDOK
    Quit

  NotRunning:

FunctionEnd

/** Components_Page_pre()  Call back function
 *
 * Invoked by the installer before the components page is created.  We do one
 * last check that there are no locked files.  If there are we quit.  This could
 * be frustrating for a user, but we know that things will fail if we proceed.
 *
 * If this is a QUICK upgrade install, we skip the page.
 */
Function Components_Page_pre

  StrCpy $CheckRxApiLock 'false'
  Call CheckLockedFiles
  ${If} $$UserRequestAbort == 'true'
    Quit
  ${EndIf}

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

FunctionEnd

/** Components_Page_show()  Call back function
 *
 * Invoked by the installer right before the components page is shown.
 *
 * If this is an upgrade install, we don't allow the user to quit from here on
 * out.  On this page we also don't let the user go back
 *
 * When it is not an upgrade install, nothing is done.
 */
Function Components_Page_show

  ${If} $DoUpgrade == 'true'
    ; Disable Back button
    GetDlgItem $0 $HWNDPARENT 3
    EnableWindow $0 0

    ; Disable the components list view control
    EnableWindow $mui.ComponentsPage.Components 0

    ; Change the descriptive text
    SendMessage $mui.ComponentsPage.Text ${WM_SETTEXT} 0 \
      "STR:These components of ${LONGNAME} ${VERSION} wil be installed.  The component list can not be \
      changed for an upgrade type of install.  Click Next to continue."

    Call PageDisableQuit
  ${EndIf}

FunctionEnd

/** Directory_Page_pre()  Call back function
 *
 * Invoked by the installer before the directory page is created.
 *
 * If this is a QUICK upgrade install, we skip the page.
 */
Function Directory_Page_pre

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

FunctionEnd

/** Directory_Page_show()  Call back function
 *
 * Invoked by the installer right before the directory page is shown.
 *
 * If this is an upgrade install, the install location can not be changed.  We
 * use function to show the user the install location, but not let them change
 * the location.
 *
 * When it is not an upgrade install, nothing is done.
 */
Function Directory_Page_show

  ${If} $DoUpgrade == 'true'
    SendMessage $mui.DirectoryPage.Text ${WM_SETTEXT} 0 \
      "STR:Setup will install ${LONGNAME} ${VERSION} in the following folder.  The location can not be \
      changed for an upgrade type of install.  Click Next to continue."

    EnableWindow $mui.DirectoryPage.Directory 0
    EnableWindow $mui.DirectoryPage.BrowseButton 0

    Call PageDisableQuit
  ${EndIf}

FunctionEnd

/** Finish_Page_pre()  Call back function
 *
 * Invoked by the installer before the finish page is created.
 *
 * If this is an upgrade install, the creation or not, of the desktop icon can
 * not be changed.  So we always create the icon here if we are going to.
 *
 * If this is a QUICK upgrade install, we abort here so that the finish page is
 * not shown at all
 *
 * At the time this is run, the registry values have been deleted.  The value in
 * RegVal_desktop_icon is the value in the registry when this installer was
 * started.  If there is an existing ooRexx, the ooRexx uninstaller is run and
 * it always deletes all the existing registry entries.  If we are doing an
 * upgrade and creating the icon we write a 1 for the registry value.  If we are
 * not creating the icon we write a 0 just to be tidy.  Leaving out the entry
 * altogether would be fine.  If we are not doing an upgrade, we do not do
 * anything here, the Finish page will be shown and the CreateDesktopIcon()
 * function will do the appropriate thing.
 */
Function Finish_Page_pre

  ${If} $DoUpgrade == 'true'
    ${If} $RegVal_desktop_icon == '1'
      CreateShortcut "$DESKTOP\Open Object Rexx Resources.lnk" "$SMPROGRAMS\${LONGNAME}\" "" "$INSTDIR\rexx.exe"
      Call OpenUninstallLog
      ${AddItem} "$DESKTOP\Open Object Rexx Resources.lnk"
      WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${SHORTNAME}" "CreateDesktopIcon" 1
      Call CloseUninstallLog
    ${else}
      WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${SHORTNAME}" "CreateDesktopIcon" 0
    ${EndIf}
    ${If} $DoUpgradeQuick == 'true'
      Abort
    ${EndIf}
  ${EndIf}

FunctionEnd

/** Finish_Page_show()  Call back function
 *
 * Invoked by the installer right before the finish page is shown.
 *
 * Note that if this is a quick upgrade type, we never get here.
 *
 * If this is an upgrade install, the create desktop icon value can not be
 * changed.  We use function to show the create desktop icon value by checking
 * or not checking the check box, but we disable the check box.  For the show
 * getting started with Windows ooRex checkbox, we assume on an upgrade install,
 * the user doesn't need this at all and we make the check box invisible.
 *
 * When it is not an upgrade install, nothing is done.
 */
Function Finish_Page_show

  ${If} $DoUpgrade == 'true'
    SendMessage $mui.FinishPage.Text ${WM_SETTEXT} 0 \
      "STR:${LONGNAME} ${VERSION} has been installed on your computer.  Whether a Desktop \
      Icon has been created or not is indicated by the state of the check box. This can not \
      be changed for an upgrade type of install.$\n$\n  Click Finish to close this Wizard."

    SendMessage $mui.FinishPage.Run ${BM_SETCHECK} ${BST_CHECKED} $RegVal_desktop_icon
    EnableWindow $mui.FinishPage.Run 0

    ShowWindow $mui.FinishPage.ShowReadme ${SW_HIDE}

    ; Show or not show the link?
    ShowWindow $mui.FinishPage.Link ${SW_HIDE}

  ${EndIf}

FunctionEnd

/** File_Associations_page()  Custom page function.
 *
 * Allows the user to specify whether they want to use Windows file associations
 * or not.
 *
 * The page is not shown when doing an upgrade type of install.
 */
Function File_Associations_page

  ${If} $DoUpgrade == 'true'
    Abort
  ${EndIf}

  !insertmacro MUI_HEADER_TEXT "Associate file extensions with the ooRexx executables." \
                               "Any, or all, of the ooRexx executables (rexx.exe, rexxhide.exe, or rexxpaws.exe) \
                               can be associated with a file extension."

  nsDialogs::Create 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_OnBack} File_Associations_leave

  ${NSD_CreateLabel} 0 0 100% 120u \
    "Windows file associations define how Windows treats a file type on your system. \
    File associations control, among other things, what happens when a user double-clicks a \
    file, which icon appears for a file by default, and how the file appears when viewed \
    in Windows Explorer.$\n$\n\
    Associating a file extension with an ooRexx executable allows Rexx programs to be executed by \
    double clicking them in Windows explorer, and to be run from the command line by just typing \
    their file name.  In addition, you can specify an editor for the file type.  This editor is \
    used when the Edit item of the context menu for the file is selected.$\n$\n\
    Check the check box to have the installer create file associations.  The following pages \
    will allow you to specify which associations are created.  Uncheck the check box if you \
    do not want any associations to be created."

  Pop $Label_One

  ${NSD_CreateCheckBox} 0 122u 100% 8u "Create Windows file associations"
  Pop $Use_File_Associations_CK
  ${NSD_SetState} $Use_File_Associations_CK $Use_File_Associations_CK_state

  nsDialogs::Show

FunctionEnd

/** File_Associations_leave()  Call back function.
 *
 * Invoked when the user clicks the Back or Next buttons on the File
 * Associations page.  Saves the state of the Use File Associations check box.
 */
Function File_Associations_leave

  ${NSD_GetState} $Use_File_Associations_CK $Use_File_Associations_CK_state

FunctionEnd

/** SendTo_Items_page()  Custom page function.
 *
 * Allows the user to create 'Send To' items for the Rexx executables.
 *
 * The page is skipped if we are doing a quick upgrade.
 */
Function SendTo_Items_page

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
    !insertmacro MUI_HEADER_TEXT "The Send To items that will be created." \
                                 "Which Send To items will be created can not be changed during an upgrade \
                                 type of install."
  ${else}
    !insertmacro MUI_HEADER_TEXT "Create 'Send To' items for the Rexx executables." \
                                 "'Send To' items can be used instead of file associations, or in addition \
                                 to file associations."
  ${EndIf}

  nsDialogs::Create 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_OnBack} SendTo_Items_leave

  ${NSD_CreateLabel} 0u 0u 100% 72u \
    "The 'Send To' context menu item for objects displayed in the Windows Explore contains a list of \
    programs that the object can be 'sent to.'  Typically, the items in the list are executables that \
    can process the file or directory object sent to them.  'Sending' your Rexx program to one of the \
    Rexx executables will execute your program.$\n$\n\
    Rather than create a file association for rexxhide.exe and rexxpaws.exe you may wish to create a \
    'Send To' item for those executables.  Or create both a file association and 'Send To' items for \
    those executables.  Usually a file association is created for rexx.exe and not a 'Send To' item."

  Pop $Label_One

  ${NSD_CreateCheckBox}   0u   80u 100%  8u "Create 'Send To' Rexx item  (Typically this is not done.)"
  Pop $SendTo_rexx_CK

  ${NSD_CreateCheckBox}    0u 100u 100%  8u "Create 'Send To' Rexx Hide (rexxhide.exe) item"
  Pop $SendTo_rexxHide_CK

  ${NSD_CreateCheckBox}    0u 120u 100%  8u "Create 'Send To' Rexx Pause (rexxpaws.exe) item"
  Pop $SendTo_rexxPaws_CK

  ${NSD_SetState} $SendTo_rexx_CK $SendTo_rexx_CK_state
  ${NSD_SetState} $SendTo_rexxhide_CK $SendTo_rexxHide_CK_state
  ${NSD_SetState} $SendTo_rexxpaws_CK $SendTo_rexxPaws_CK_state

  ${If} $DoUpgrade == 'true'
    EnableWindow $Label_One 0
	  EnableWindow $SendTo_rexx_CK 0
	  EnableWindow $SendTo_rexxHide_CK 0
	  EnableWindow $SendTo_rexxPaws_CK 0
    Call PageDisableQuit
	${EndIf}

  nsDialogs::Show

FunctionEnd

/** SendTo_Items_leave()  Call back function.
 *
 * This function is called when the Send To Items page is left.  The state of
 * the dialog controls is saved.
 */
Function SendTo_Items_leave

  ${NSD_GetState} $SendTo_rexx_CK $SendTo_rexx_CK_state
  ${NSD_GetState} $SendTo_rexxHide_CK $SendTo_rexxHide_CK_state
  ${NSD_GetState} $SendTo_rexxPaws_CK $SendTo_rexxPaws_CK_state

FunctionEnd

/** Associate_rexx_page()  Custom page function.
 *
 * Presents the option to the user of creating a file association for rexx.exe
 *
 * The page is skipped if not using file associations, or if we are doing a
 * quick upgrade.
 */
Function Associate_rexx_page

  ${If} $Use_File_Associations_CK_state == ${BST_UNCHECKED}
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
    !insertmacro MUI_HEADER_TEXT "The file extension for rexx.exe and Rexx program editor choices." \
                                 "These choices can not be changed during an upgrade type of install."
  ${else}
    !insertmacro MUI_HEADER_TEXT "Associate a file extension with rexx.exe." "Pick the editor to be used when the Edit \
                                 item of the context menu is selected."
  ${EndIf}

  nsDialogs::Create 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_OnBack} Associate_rexx_leave

  ${NSD_CreateLabel} 0u 0u 100% 16u \
    "Select the editor to be used with your ooRexx file type(s).  This adds the Edit menu item to \
    the context menu of the file type.  The same editor is used for all file types."

  Pop $Label_One

  ; Editor line
  ${NSD_CreateLabel}     0u 20u 60u  8u "Full path to editor:"
  Pop $0  ; Discarded

  ${NSD_CreateText}      0u 30u 185u 12u $Rexx_editor_text
  Pop $Rexx_editor_EDIT

  ${NSD_CreateButton}   190u 28u  45u 16u "Browse..."
  Pop $Rexx_editor_PB

	System::Call shlwapi::SHAutoComplete(i$Rexx_editor_EDIT, i${SHACF_FILESYSTEM})


  ${NSD_CreateLabel} 0u 60u 100% 24u \
    "By default in ${LONGNAME} installations the Rexx interpreter, rexx.exe, is associated with the \
    ${DefRexxExt} extension using the file type name of ${DefRexxFType}.  However, you can change these values if \
    you care to."

  Pop $Label_Two

  ${NSD_CreateGroupBox} 0u 90u 100% 44u "File Association for rexx.exe"
  Pop $0  ; Discarded

  ${NSD_CreateCheckBox} 8u  104u 80% 8u "Create rexx.exe file association"
  Pop $Associate_rexx_CK

  ${NSD_SetState} $Associate_rexx_CK $Associate_rexx_CK_state

  ; Extension line
  ${NSD_CreateLabel}     16u  116u  75u  8u "Extension (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      91u  114u  36u 12u $Rexx_ext_text
  Pop $Rexx_ext_EDIT

  ; File type line
  ${NSD_CreateLabel}     137u 116u  90u  8u "File type name (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      228u 114u  46u 12u $Rexx_ftype_text
  Pop $Rexx_ftype_EDIT

  ${NSD_SetState} $Associate_rexx_CK $Associate_rexx_CK_state
  ${NSD_SetState} $SendTo_rexx_CK $SendTo_rexx_CK_state

  ${If} $Associate_rexx_CK_state == ${BST_UNCHECKED}
  ${orif} $DoUpgrade == 'true'
	  EnableWindow $Rexx_ext_EDIT 0
	  EnableWindow $Rexx_ftype_EDIT 0

    ${If} $DoUpgrade == 'true'
  	  EnableWindow $Rexx_editor_EDIT 0
  	  EnableWindow $Rexx_editor_PB 0
  	  EnableWindow $Associate_rexx_CK 0
      EnableWindow $Label_One 0
      EnableWindow $Label_Two 0
      Call PageDisableQuit
  	${EndIf}
	${EndIf}

  ${NSD_OnClick} $Associate_rexx_CK EnableRexxAssociation
  ${NSD_OnClick} $Rexx_editor_PB Get_rexx_editor_file

  nsDialogs::Show

FunctionEnd

/** Associate_rexx_leave()  Call back function.
 *
 * This function is called when the Rexx association page is left.  We check
 * that the text fields are 'sane' and return the user to the page if they
 * are not.  If the fields are good, the state of the dialog controls is saved.
 */
Function Associate_rexx_leave

  ${NSD_GetState} $Associate_rexx_CK $Associate_rexx_CK_state

  ${If} $Associate_rexx_CK_state == ${BST_CHECKED}
    ${NSD_GetText} $Rexx_ext_EDIT $0
    ${NSD_GetText} $Rexx_ftype_EDIT $1

    ; If either the extension field or the ftype field are blank, abort.
    ${If} $0 == ""
    ${orif} $1 == ""
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Creating a file association requires that$\n\
        both the file extension and the file type field$\n\
        be filed in."

      ${If} $0 == ""
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

    ; Copy the first char of the ext field to $0 if not a '.', abort.
    StrCpy $2 $0 1
    ${If} $2 != "."
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Please include the leading dot '.' of the file$\n\
        extension."
      SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ext_EDIT 1
      Abort
    ${EndIf}

    ; Check that the user did not include any spaces in either field. If so abort
    push $0
    call CheckForSpaces
    pop $2
    push $1
    call CheckForSpaces
    pop $3

    ${If} $2 > 0
    ${orif} $3 > 0
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Neither the file extension field nor the file$\n\
        type name field can contain a space."

      ${If} $2 > 0
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $Rexx_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

  ${EndIf}


  ; Okay text fields are okay.  If editor field is blank, it is just not used.
  ${NSD_GetText} $Rexx_ext_EDIT $Rexx_ext_text
  ${NSD_GetText} $Rexx_ftype_EDIT $Rexx_ftype_text
  ${NSD_GetText} $Rexx_editor_EDIT $Rexx_editor_text

FunctionEnd

/** Get_rexx_editor_file()
 *
 * Puts up a file open dialog and allows the user to select a file.  If the
 * user does not cancel, the edit control is updated with the file selected.
 */
Function Get_rexx_editor_file
	Pop $Rexx_editor_PB
	${NSD_GetText} $Rexx_editor_EDIT $0

  nsDialogs::SelectFileDialog open $0 "*.exe"
  pop $0
  ${If} $0 != ""
  	${NSD_SetText} $Rexx_editor_EDIT $0
  ${EndIf}

FunctionEnd

/** EnableRexxAssociation()
 *
 * Called when the user clicks on the Create rexx.exe file association check
 * box.  Disables, or enables, the controls depending on if the check box is
 * checked or not.
 */
Function EnableRexxAssociation
	Pop $Associate_rexx_CK
	${NSD_GetState} $Associate_rexx_CK $0

	${If} $0 == 1
	  EnableWindow $Rexx_ext_EDIT 1
	  EnableWindow $Rexx_ftype_EDIT 1
	${Else}
	  EnableWindow $Rexx_ext_EDIT 0
	  EnableWindow $Rexx_ftype_EDIT 0
	${EndIf}
FunctionEnd

/** Associate_otherExes_page()  Custom page function.
 *
 * This is a custom page
 *
 *
 *
 */
Function Associate_otherExes_page

  ${If} $Use_File_Associations_CK_state == ${BST_UNCHECKED}
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
    !insertmacro MUI_HEADER_TEXT "The file extension chocies for rexxhide.exe. and rexxpaws.exe" \
                                 "These choices can not be changed during an upgrade type of install."
  ${else}
    !insertmacro MUI_HEADER_TEXT "Associate a file extension with rexxhide.exe and / or rexxpaws.exe" \
                                 "rexxhide default file extension: $\"${DefRexxHideExt}$\" file type: $\"${DefRexxHideFType}$\"$\n\
                                 rexpaws default file extension: $\"${DefRexxPawsExt}$\" file type: $\"${DefRexxPawsFType}$\"."
  ${EndIf}

  nsDialogs::Create 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${NSD_OnBack} Associate_otherExes_leave

  /* Controls for Rexx Hide */
  ${NSD_CreateLabel} 0u 0u 100% 8u \
    "rexxhide runs Rexx programs without creating a console window."

  Pop $Label_One

  ${NSD_CreateGroupBox} 0u 12u 100% 44u "File Association for rexxhide.exe"
  Pop $0  ; Discarded

  ${NSD_CreateCheckBox} 8u 24u 80% 8u "Create rexxhide.exe file association"
  Pop $Associate_rexxhide_CK

  ${NSD_SetState} $Associate_rexxhide_CK $Associate_rexxhide_CK_state

  ; Extension line
  ${NSD_CreateLabel}     16u  38u   75u  8u "Extension (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      91u  36u  36u 12u $RexxHide_ext_text
  Pop $RexxHide_ext_EDIT

  ; File type line
  ${NSD_CreateLabel}     137u 38u   90u  8u "File type name (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      228u 36u  46u 12u $RexxHide_ftype_text
  Pop $RexxHide_ftype_EDIT


  /* Controls for Rexx Paws */
  ${NSD_CreateLabel} 0u 70u 100% 16u \
    "rexxpaws runs a Rexx programs and 'pauses' until the user hits the Enter key, allowing any output to \
    be read before the console window closes."

  Pop $Label_Two

  ${NSD_CreateGroupBox} 0u 92u 100% 44u "File Association for rexxpaws.exe"
  Pop $0  ; Discarded

  ${NSD_CreateCheckBox} 8u 104u 80% 8u "Create rexxpaws.exe file association"
  Pop $Associate_rexxpaws_CK

  ${NSD_SetState} $Associate_rexxpaws_CK $Associate_rexxpaws_CK_state

  ; Extension line
  ${NSD_CreateLabel}     16u  118u  75u  8u "Extension (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      91u  116u  36u 12u $RexxPaws_ext_text
  Pop $RexxPaws_ext_EDIT

  ; File type line
  ${NSD_CreateLabel}     137u 118u  90u  8u "File type name (no spaces):"
  Pop $0  ; Discarded

  ${NSD_CreateText}      228u 116u  46u 12u $RexxPaws_ftype_text
  Pop $RexxPaws_ftype_EDIT

  ${If} $DoUpgrade == 'true'
    EnableWindow $Associate_rexxhide_CK 0
	  EnableWindow $RexxHide_ext_EDIT 0
	  EnableWindow $RexxHide_ftype_EDIT 0

  	EnableWindow $Associate_rexxpaws_CK 0
	  EnableWindow $RexxPaws_ext_EDIT 0
	  EnableWindow $RexxPaws_ftype_EDIT 0

    EnableWindow $Label_One 0
    EnableWindow $Label_Two 0

    Call PageDisableQuit
  ${else}
    ${If} $Associate_rexxhide_CK_state == ${BST_UNCHECKED}
  	  EnableWindow $RexxHide_ext_EDIT 0
  	  EnableWindow $RexxHide_ftype_EDIT 0
  	${EndIf}

    ${If} $Associate_rexxpaws_CK_state == ${BST_UNCHECKED}
  	  EnableWindow $RexxPaws_ext_EDIT 0
  	  EnableWindow $RexxPaws_ftype_EDIT 0
    ${EndIf}
  ${EndIf}

  ${NSD_OnClick} $Associate_rexxhide_CK EnableRexxHideAssociation
  ${NSD_OnClick} $Associate_rexxpaws_CK EnableRexxPawsAssociation

  nsDialogs::Show

FunctionEnd

/** Associate_otherExes_leave()  Call back function.
 *
 * This function is called when the RexxHide association page is left.  We check
 * that the text fields are 'sane' and return the user to the page if they
 * are not.  If the text field values are good, the state of the dialog contorls
 * is saved.
 */
Function Associate_otherExes_leave

  /* Check the Rexx Hide controls */
  ${NSD_GetState} $Associate_rexxhide_CK $Associate_rexxhide_CK_state

  ${If} $Associate_rexxhide_CK_state == ${BST_CHECKED}
    ${NSD_GetText} $RexxHide_ext_EDIT $0
    ${NSD_GetText} $RexxHide_ftype_EDIT $1

    ; If either the extension field or the ftype field are blank, abort.
    ${If} $0 == ""
    ${orif} $1 == ""
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Creating a file association requires that$\n\
        both the file extension and the file type field$\n\
        be filed in."

      ${If} $0 == ""
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxHide_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxHide_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

    ; Copy the first char of the ext field to $0 if not a '.', abort.
    StrCpy $2 $0 1
    ${If} $2 != "."
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Please include the leading dot '.' of the file$\n\
        extension."
      SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxHide_ext_EDIT 1
      Abort
    ${EndIf}

    ; Check that the user did not include any spaces in either field. If so abort
    push $0
    call CheckForSpaces
    pop $2
    push $1
    call CheckForSpaces
    pop $3

    ${If} $2 > 0
    ${orif} $3 > 0
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Neither the file extension field nor the file$\n\
        type name field can contain a space."

      ${If} $2 > 0
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxHide_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxHide_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}


  ${EndIf}

  /* Check the Rexx Paws controls */
  ${NSD_GetState} $Associate_rexxpaws_CK $Associate_rexxpaws_CK_state

  ${If} $Associate_rexxpaws_CK_state == ${BST_CHECKED}
    ${NSD_GetText} $RexxPaws_ext_EDIT $0
    ${NSD_GetText} $RexxPaws_ftype_EDIT $1

    ; If either the extension field or the ftype field are blank, abort.
    ${If} $0 == ""
    ${orif} $1 == ""
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Creating a file association requires that$\n\
        both the file extension and the file type field$\n\
        be filed in."

      ${If} $0 == ""
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxPaws_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxPaws_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

    ; Copy the first char of the ext field to $0 if not a '.', abort.
    StrCpy $2 $0 1
    ${If} $2 != "."
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Please include the leading dot '.' of the file$\n\
        extension."
      SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxPaws_ext_EDIT 1
      Abort
    ${EndIf}

    ; Check that the user did not include any spaces in either field. If so abort
    push $0
    call CheckForSpaces
    pop $2
    push $1
    call CheckForSpaces
    pop $3

    ${If} $2 > 0
    ${orif} $3 > 0
      MessageBox MB_OK|MB_ICONEXCLAMATION \
        "Neither the file extension field nor the file$\n\
        type name field can contain a space."

      ${If} $2 > 0
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxPaws_ext_EDIT 1
      ${else}
        SendMessage $Dialog ${WM_NEXTDLGCTL} $RexxPaws_ftype_EDIT 1
      ${EndIf}
      Abort
    ${EndIf}

  ${EndIf}

  ; Okay text fields are okay.
  ${NSD_GetText} $RexxHide_ext_EDIT $RexxHide_ext_text
  ${NSD_GetText} $RexxHide_ftype_EDIT $RexxHide_ftype_text
  ${NSD_GetText} $RexxPaws_ext_EDIT $RexxPaws_ext_text
  ${NSD_GetText} $RexxPaws_ftype_EDIT $RexxPaws_ftype_text

FunctionEnd

/** EnableRexxHideAssociation()
 *
 * Called when the user clicks on the Create rexxhide.exe file association check
 * box.  Disables, or enables, the controls depending on if the check box is
 * checked or not.
 */
Function EnableRexxHideAssociation
	Pop $Associate_rexxhide_CK
	${NSD_GetState} $Associate_rexxhide_CK $0

	${If} $0 == 1
	  EnableWindow $RexxHide_ext_EDIT 1
	  EnableWindow $RexxHide_ftype_EDIT 1
	${Else}
	  EnableWindow $RexxHide_ext_EDIT 0
	  EnableWindow $RexxHide_ftype_EDIT 0
	${EndIf}
FunctionEnd

/** EnableRexxPawsAssociation()
 *
 * Called when the user clicks on the Create rexxpaws.exe file association check
 * box.  Disables, or enables, the controls depending on if the check box is
 * checked or not.
 */
Function EnableRexxPawsAssociation
	Pop $Associate_rexxpaws_CK
	${NSD_GetState} $Associate_rexxpaws_CK $0

	${If} $0 == 1
	  EnableWindow $RexxPaws_ext_EDIT 1
	  EnableWindow $RexxPaws_ftype_EDIT 1
	${Else}
	  EnableWindow $RexxPaws_ext_EDIT 0
	  EnableWindow $RexxPaws_ftype_EDIT 0
	${EndIf}
FunctionEnd

/** Confirm_page()  Custom page function.
 *
 * Gives the user one last chance to go back and change any settings.
 *
 * The page is skipped if we are doing an upgrade type of install.
 */
Function Confirm_page

  ${If} $DoUpgrade == 'true'
  ${andif} $DoUpgradeQuick == 'true'
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
    !insertmacro MUI_HEADER_TEXT "${LONGNAME} is ready for installation." \
                                 "Installation options remain the same for an upgrade type of installation \
                                 of ${LONGNAME}."
  ${else}
    !insertmacro MUI_HEADER_TEXT "${LONGNAME} is ready for installation." \
                                 "All options for ${LONGNAME} have been collected."
  ${EndIf}

  nsDialogs::Create 1018
  Pop $Dialog

  ${If} $Dialog == error
    Abort
  ${EndIf}

  ${If} $DoUpgrade == 'true'
    ${NSD_CreateLabel} 0u 0u 100% 72u \
    "Click the Install button to begin installation.  Click the Back button if you \
     wish to review the installation options.  An upgrade type of installation can \
     not be canceled at this point."
  ${else}
    ${NSD_CreateLabel} 0u 0u 100% 72u \
    "All the parameters needed to install ${LONGNAME} on your system have been \
    gathered together.$\n$\n\
    Click the Install button to begin installation.  Click the Back button to \
    review or change any settings.  Click the Cancel button to abort the installation \
    altogether."
  ${EndIf}

  Pop $Label_One

  ${If} $DoUpgrade == 'true'
    Call PageDisableQuit
  ${EndIf}

  nsDialogs::Show

FunctionEnd

/** PageDisableQuit()
 *
 * Prevents the user from closing (quitting) the installer from the current
 * page.  The function could be generic, but at this point only works if we
 * are doing an upgrade install.
 */
Function PageDisableQuit

  ; Really this should only be called when DoUpgrade is true, but we'll use
  ; a little defensive programming.
  ${If} $DoUpgrade == 'true'
    ; Disable the close button on title bar.
    push $1
    System::Call "user32::GetSystemMenu(i $HWNDPARENT,i 0) i.s"
    pop $1
    System::Call "user32::EnableMenuItem(i $1,i 0xF060,i 1)"
    pop $1

    ; Disable Cancel button
    GetDlgItem $0 $HWNDPARENT 2
    EnableWindow $0 0

    ; Set focus to the Next button
    GetDlgItem $0 $HWNDPARENT 1
    SendMessage $HWNDPARENT ${WM_NEXTDLGCTL} $0 1
  ${EndIf}

FunctionEnd

/** DoSendToItems()
 *
 * Create 'Send To' items depending on what the user specified.  This is only
 * called when we are not doing an upgrade type of install.
 *
 * Note that we do not add the shortcut files to the uninstall log.  Deleting
 * the files is done separately from the uninstall log usage because there is
 * no (easy) way to tell which file is being deleted when using the uninstall
 * log.
 */
Function DoSendToItems

  ; Save the user specified settings into the registry variables so the are
  ; written to the registry correctly.
  StrCpy $RegVal_sendTo_rexx $SendTo_rexx_CK_state
  StrCpy $RegVal_sendTo_rexxHide $SendTo_rexxHide_CK_state
  StrCpy $RegVal_sendTo_rexxPaws $SendTo_rexxPaws_CK_state

  SetOutPath $INSTDIR
  ${If} $SendTo_rexx_CK_state == ${BST_CHECKED}
    CreateShortCut "$SENDTO\ooRexx.lnk" "$INSTDIR\rexx.exe" "" "" "" SW_SHOWNORMAL "" "ooRexx"
    DetailPrint "Created Send To rexx.exe item"
  ${EndIf}

  ${If} $SendTo_rexxHide_CK_state == ${BST_CHECKED}
    CreateShortCut "$SENDTO\ooRexx with no console (rexxhide).lnk" "$INSTDIR\rexxhide.exe" "" "" "" SW_SHOWNORMAL "" "ooRexx with no console (rexxhide)"
    DetailPrint "Created Send To rexxhide.exe item"
  ${EndIf}

  ${If} $SendTo_rexxPaws_CK_state == ${BST_CHECKED}
    CreateShortCut "$SENDTO\ooRexx with pause (rexxpaws).lnk" "$INSTDIR\rexxpaws.exe" "" "" "" SW_SHOWNORMAL "" "ooRexx with pause (rexxpaws)"
    DetailPrint "Created Send To rexxpaws.exe item"
  ${EndIf}

FunctionEnd

/** DoFileAssociations()
 *
 * Does the file associations for ooRexx.  Only called when not doing an
 * upgrade.
 *
 * We do two things:
 *   Fill in the values stored in the uninstall section for ooRexx.  These
 *   values tell the uninstaller, when it runs, what it should delete from the
 *   registry.
 *
 *   Write out the actual file associations selected by the user to the
 *   registry.
 */
Function DoFileAssociations

  ; Set everything to blank, then fill in those values the user specified.
  StrCpy $RegVal_rexxAssociation ""
  StrCpy $RegVal_rexxEditor ""
  StrCpy $RegVal_rexxHideAssociation ""
  StrCpy $RegVal_rexxPawsAssociation ""

  ${If} $Use_File_Associations_CK_state == ${BST_UNCHECKED}
    DetailPrint "Do not use Windows file associations specified."
    Return
  ${EndIf}

  ${If} $Associate_rexx_CK_state == ${BST_CHECKED}
    StrCpy $AssociationProgramName 'rexx.exe'
    StrCpy $RegVal_rexxAssociation '$Rexx_ext_text $Rexx_ftype_text'
    StrCpy $RegVal_rexxEditor '$Rexx_editor_text'

    Call AssociateExtensionWithExe
  ${EndIf}

  ${If} $Associate_rexxhide_CK_state == ${BST_CHECKED}
    StrCpy $AssociationProgramName 'rexxhide.exe'
    StrCpy $RegVal_rexxHideAssociation '$RexxHide_ext_text $RexxHide_ftype_text'
    StrCpy $RegVal_rexxEditor '$Rexx_editor_text'

    Call AssociateExtensionWithExe
  ${EndIf}

  ${If} $Associate_rexxpaws_CK_state == ${BST_CHECKED}
    StrCpy $AssociationProgramName 'rexxpaws.exe'
    StrCpy $RegVal_rexxPawsAssociation '$RexxPaws_ext_text $RexxPaws_ftype_text'
    StrCpy $RegVal_rexxEditor '$Rexx_editor_text'

    Call AssociateExtensionWithExe
  ${EndIf}

  System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
FunctionEnd

/** DoEnvVariables()
 *
 * Sets up the variable environemnt variables.
 */
Function DoEnvVariables

    Push "REXX_HOME"
    Push $INSTDIR
    Push $IsAdminUser ; "true" or "false"
    Call WriteEnvStr

    ; Add the install directory to the PATH env variable, either system wide or
    ; user-specific
    Push $INSTDIR
    Push $IsAdminUser ; "true" or "false"
    Push "PATH"
    Call AddToPath

    ; Do the PATHEXT extensions
    Call AddToPathExt
FunctionEnd

/** AssociateExtensionWithExe()
 *
 * Associates a file extension and file type with one of the ooRexx executables,
 * rexx.exe, rexxhide.exe, or rexxpaws.  We are only called when we have
 * something to do.
 *
 * TODO - I added the section to install into the user customizable area some
 *        years ago.  Really what we should be doing, rather than this IsAdmin
 *        stuff is deciding if this is a machine-wide install (All Users) or
 *        a single-user install.  Then use SHCTX or SHELL_CONTEXT to just write
 *        once. SHCTX will use HKCR if it is an all users install and HKCU for
 *        a single user install.
 *
 */
Function AssociateExtensionWithExe

  ; We will put the file extension in $0, the ftype in $1, and the editor file
  ; name in $2
  ${If} $AssociationProgramName == 'rexx.exe'
    ${StrTok} $0 $RegVal_rexxAssociation " " "0" "0"
    ${StrTok} $1 $RegVal_rexxAssociation " " "1" "0"
    StrCpy $AssociationText "ooRexx Rexx Program"
    StrCpy $AssociationEditor '$RegVal_rexxEditor'
  ${elseif} $AssociationProgramName == 'rexxhide.exe'
    ${StrTok} $0 $RegVal_rexxHideAssociation " " "0" "0"
    ${StrTok} $1 $RegVal_rexxHideAssociation " " "1" "0"
    StrCpy $AssociationText "ooRexx Rexx GUI Program"
    StrCpy $AssociationEditor '$RegVal_rexxEditor'
  ${elseif} $AssociationProgramName == 'rexxpaws.exe'
    ${StrTok} $0 $RegVal_rexxPawsAssociation " " "0" "0"
    ${StrTok} $1 $RegVal_rexxPawsAssociation " " "1" "0"
    StrCpy $AssociationText "ooRexx Rexx pausing Program"
    StrCpy $AssociationEditor "$RegVal_rexxEditor"
  ${else}
    DetailPrint "Unrecoverable ERROR. The ftype association executable: $AssociationProgramName is not recognized."
    Goto DoneWithRexxExe
  ${EndIf}

  ${If} $0 == ''
  ${orif} $1 == ''
    DetailPrint "Unrecoverable ERROR.  Empty string in $AssociationProgramName association"
    DetailPrint "  Word one=<$0> word two=<$1>"
    Goto DoneWithRexxExe
  ${EndIf}

  ClearErrors
  ; Write key $0 (.rex for example) with default value of $1 (RexxScript for example.)
  WriteRegStr HKCR $0 "" $1
  IfErrors TryCurrentUser
  DetailPrint "Registered $0 extension as ftype $1 to open with $AssociationProgramName for all users"
  Goto WriteHKCRRegKeys

  TryCurrentUser:
  ; Failed to write to the registy, try the user customizable area.
  ClearErrors
  WriteRegStr HKCU $0 "" $1
  IfErrors 0
    DetailPrint "Could NOT associate $0 extension with $AssociationProgramName for either all users or the current user"
    Goto DonewithRexxExe

  DetailPrint "Registered $0 extension as ftype $1 to open with $AssociationProgramName for the current user."
  WriteRegStr HKCU "SOFTWARE\Classes\$1" "" $AssociationText
  WriteRegStr HKCU "SOFTWARE\Classes\$1\shell" "" "open"
  WriteRegStr HKCU "SOFTWARE\Classes\$1\DefaultIcon" "" "$INSTDIR\$AssociationProgramName,0"
  WriteRegStr HKCU "SOFTWARE\Classes\$1\shell\open" "" "Run"
  WriteRegStr HKCU "SOFTWARE\Classes\$1\shell\open\command" "" '"$INSTDIR\$AssociationProgramName" "%1" %*'

  ${If} $AssociationEditor != ""
    WriteRegStr HKCU "SOFTWARE\Classes\$1\shell\edit" "" "Edit"
    WriteRegStr HKCU "SOFTWARE\Classes\$1\shell\edit\command" "" '"$AssociationEditor" "%1"'
  ${EndIf}

  WriteRegStr HKCU "SOFTWARE\Classes\$1\shellex\DropHandler" "" "{60254CA5-953B-11CF-8C96-00AA00B8708C}"
  Goto DoneWithRexxExe

  WriteHKCRRegKeys:
  WriteRegStr HKCR "$1" "" $AssociationText
  WriteRegStr HKCR "$1\shell" "" "open"
  WriteRegStr HKCR "$1\DefaultIcon" "" "$INSTDIR\$AssociationProgramName,0"
  WriteRegStr HKCR "$1\shell\open" "" "Run"
  WriteRegStr HKCR "$1\shell\open\command" "" '"$INSTDIR\$AssociationProgramName" "%1" %*'

  ${If} $AssociationEditor != ""
    WriteRegStr HKCR "$1\shell\edit" "" "Edit"
    WriteRegStr HKCR "$1\shell\edit\command" "" '"$AssociationEditor" "%1"'
  ${EndIf}

  WriteRegStr HKCR "$1\shellex\DropHandler" "" "{60254CA5-953B-11CF-8C96-00AA00B8708C}"

  DoneWithRexxExe:
FunctionEnd

/** SetDefaultFileAssociation()
 *
 * Use to set the variable values for all the file association controls to the
 * default.
 */
Function SetDefaultFileAssociation
  StrCpy $Use_File_Associations_CK_state '${BST_CHECKED}'

  StrCpy $Associate_rexx_CK_state '${BST_CHECKED}'
  StrCpy $Rexx_ext_text ${DefRexxExt}
  StrCpy $Rexx_ftype_text ${DefRexxFType}
  StrCpy $Rexx_editor_text "$WINDIR\System32\NotePad.exe"

  StrCpy $Associate_rexxhide_CK_state '${BST_UNCHECKED}'
  StrCpy $RexxHide_ext_text ${DefRexxHideExt}
  StrCpy $RexxHide_ftype_text ${DefRexxHideFType}

  StrCpy $Associate_rexxpaws_CK_state '${BST_UNCHECKED}'
  StrCpy $RexxPaws_ext_text ${DefRexxPawsExt}
  StrCpy $RexxPaws_ftype_text ${DefRexxPawsFType}

FunctionEnd

/** SetBlankFileAssociation()
 *
 * Use to set the variable values for all the file association controls to the
 * the empty string.
 */
Function SetBlankFileAssociation
  StrCpy $Use_File_Associations_CK_state '${BST_UNCHECKED}'

  StrCpy $Associate_rexx_CK_state '${BST_UNCHECKED}'
  StrCpy $Rexx_ext_text ""
  StrCpy $Rexx_ftype_text ""
  StrCpy $Rexx_editor_text ""

  StrCpy $Associate_rexxhide_CK_state '${BST_UNCHECKED}'
  StrCpy $RexxHide_ext_text ""
  StrCpy $RexxHide_ftype_text ""

  StrCpy $Associate_rexxpaws_CK_state '${BST_UNCHECKED}'
  StrCpy $RexxPaws_ext_text ""
  StrCpy $RexxPaws_ftype_text ""
FunctionEnd

/** SetFileAssociationVars()
 *
 * Used to set the variable values for the file association dialog controls to
 * the proper value on start up of the installer.
 *
 * Note: we can not know at this time, if the user will elect to do an upgrade
 * type of install.  So the RegVal_* variables can not be changed.
 *
 * If there is no previous install and the reg values are blank, all the
 * variables are set to the defaults.  Likewise, if there is a previous version
 * installed, but the uninstaller version is not able to do an upgrade type of
 * install, we also set the variables to their defaults.
 *
 * Otherwise, the variables are set initially to what is in the registry.
 */
Function SetFileAssociationVars

    ${If} $PreviousVersionInstalled == 'false'
    ${andif} $RegVal_rexxAssociation == ''
      Call SetDefaultFileAssociation
    ${elseif} $UpgradeTypeAvailable == 'false'
      Call SetDefaultFileAssociation
    ${else}
      ${If} $RegVal_rexxAssociation == ''
      ${andif} $RegVal_rexxHideAssociation == ''
      ${andif} $RegVal_rexxPawsAssociation == ''
        Call SetBlankFileAssociation
      ${else}
        ; We will put the file extension in $0 and the ftype in $1

        StrCpy $Use_File_Associations_CK_state '${BST_CHECKED}'
        StrCpy $Rexx_editor_text "$RegVal_rexxEditor"

        ${If} $RegVal_rexxAssociation != ''
          ${StrTok} $0 $RegVal_rexxAssociation " " "0" "0"
          ${StrTok} $1 $RegVal_rexxAssociation " " "1" "0"

          StrCpy $Associate_rexx_CK_state '${BST_CHECKED}'
          StrCpy $Rexx_ext_text $0
          StrCpy $Rexx_ftype_text $1
        ${else}
          StrCpy $Associate_rexx_CK_state '${BST_UNCHECKED}'
        ${EndIf}

        ${If} $RegVal_rexxHideAssociation != ''
          ${StrTok} $0 $RegVal_rexxHideAssociation " " "0" "0"
          ${StrTok} $1 $RegVal_rexxHideAssociation " " "1" "0"

          StrCpy $Associate_rexxhide_CK_state '${BST_CHECKED}'
          StrCpy $RexxHide_ext_text $0
          StrCpy $RexxHide_ftype_text $1
        ${else}
          StrCpy $Associate_rexxhide_CK_state '${BST_UNCHECKED}'
        ${EndIf}

        ${If} $RegVal_rexxPawsAssociation != ''
          ${StrTok} $0 $RegVal_rexxPawsAssociation " " "0" "0"
          ${StrTok} $1 $RegVal_rexxPawsAssociation " " "1" "0"

          StrCpy $Associate_rexxpaws_CK_state '${BST_CHECKED}'
          StrCpy $RexxPaws_ext_text $0
          StrCpy $RexxPaws_ftype_text $1
        ${else}
          StrCpy $Associate_rexxpaws_CK_state '${BST_UNCHECKED}'
        ${EndIf}
      ${EndIf}
    ${EndIf}

FunctionEnd

/** SetSendToVars()
 *
 * Sets the values of the SendTo check box states on start up.  Either to the
 * defaults if there is no previous installation or a pre-4.1.0 installation.
 * Otherwise, the variables are set to what we read out of the registry.
 */
Function SetSendToVars

    ${If} $PreviousVersionInstalled == 'false'
    ${orif} $UpgradeTypeAvailable == 'false'
    ${orif} $RegVal_sendTo_rexx == ''
      StrCpy $SendTo_rexx_CK_state ${BST_UNCHECKED}
      StrCpy $SendTo_rexxHide_CK_state ${BST_CHECKED}
      StrCpy $SendTo_rexxPaws_CK_state ${BST_CHECKED}
    ${else}
      StrCpy $SendTo_rexx_CK_state $RegVal_sendTo_rexx
      StrCpy $SendTo_rexxHide_CK_state $RegVal_sendTo_rexxHide
      StrCpy $SendTo_rexxPaws_CK_state $RegVal_sendTo_rexxPaws
    ${EndIf}

FunctionEnd

/** CheckInstalledStatus()
 *
 * Helper function used to determine if there is a previous version of ooRexx
 * installed, and if so what level is the uninstaller at.
 */
Function CheckInstalledStatus

  StrCpy $PreviousVersionInstalled 'false'
  StrCpy $UpgradeTypeAvailable 'false'

  ${If} $RegVal_uninstallString != ""
    StrCpy $PreviousVersionInstalled 'true'

    ${If} $RegVal_uninstallLocation == ""
      ; No location in the registry, we'll use the installation directory.
      StrCpy $RegVal_uninstallLocation $INSTDIR
    ${EndIf}

    ${If} $RegVal_uninstallVersion != ""
      ${VersionCompare} $RegVal_uninstallVersion "4.1.0.0" $0

      ; Returned in $0: 0 == versions are equal, 1 == version is greater than 4.1.0.0, 2 == version is less than 4.1.0.0
      ${If} $0 < 2
        StrCpy $UpgradeTypeAvailable 'true'
      ${EndIf}
    ${EndIf}
  ${EndIf}

FunctionEnd


/** CheckLockedFiles()
 *
 * Helper function used to determine if files are locked.  This function is
 * called on init and right before we show the Components page.  The first time
 * rxapi may or may not be running.  The second time is after rxapi should have
 * been stopped.  If any of these files are locked, we know the install will be
 * inconsistent.  If the files are locked we give the user a chance to close
 * them and retry.
 */
Function CheckLockedFiles

  StrCpy $UserRequestAbort 'false'

check_lock_loop:

  StrCpy $KeyFileName '$RegVal_uninstallLocation\${KEYFILE1}'
  LockedList::IsFileLocked $KeyFileName
  Pop $R0
  ${If} $R0 == true
    goto rexxIsRunning
  ${EndIf}

  StrCpy $KeyFileName '$RegVal_uninstallLocation\${KEYFILE2}'
  LockedList::IsFileLocked $KeyFileName
  Pop $R0
  ${If} $R0 == true
    goto rexxIsRunning
  ${EndIf}

  ; Key file 3 is rxapi.exe.  We only check it when we think it should be
  ; stopped and we are about to do an install.
  ${If} $CheckRxApiLock == 'true'
    StrCpy $KeyFileName '$INSTDIR\${KEYFILE3}'
    LockedList::IsFileLocked $KeyFileName
    Pop $R0
    ${If} $R0 == true
      goto rexxIsRunning
    ${EndIf}
  ${EndIf}

  StrCpy $KeyFileName '$RegVal_uninstallLocation\rexxhide.exe'
  LockedList::IsFileLocked $KeyFileName
  Pop $R0
  ${If} $R0 == true
    goto rexxIsRunning
  ${EndIf}

  StrCpy $KeyFileName '$RegVal_uninstallLocation\rexxpaws.exe'
  LockedList::IsFileLocked $KeyFileName
  Pop $R0
  ${If} $R0 == true
    goto rexxIsRunning
  ${EndIf}

  StrCpy $KeyFileName '$RegVal_uninstallLocation\ooDialog.exe'
  LockedList::IsFileLocked $KeyFileName
  Pop $R0
  ${If} $R0 == true
    goto rexxIsRunning
  ${EndIf}

  StrCpy $KeyFileName '$RegVal_uninstallLocation\ooDialog.dll'
  LockedList::IsFileLocked $KeyFileName
  Pop $R0
  ${If} $R0 == true
    goto rexxIsRunning
  ${EndIf}

  goto done_out

  rexxIsRunning:
      MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION|MB_TOPMOST \
        "WARNING.  The file:$\n$\n\
          $keyFileName$\n$\n\
        is locked and can not be updated by the installer.  This indicates$\n\
        that not all Rexx programs have been halted$\n$\n\
        Continuing with the install in this case is known to cause problems.$\n$\n\
        To Retry:$\n$\n\
        Ensure all Rexx programs and processes are halted and then push$\n\
        Retry.$\n$\n\
        To Quit the install and fix the problem:$\n$\n\
        Push Cancel.  Determine which Rexx programs are open and close$\n\
        them.  Ensure no other Rexx programs or processes are open.  Then$\n\
        retry the install." \
        /SD IDCANCEL IDRETRY check_lock_loop

        StrCpy $UserRequestAbort 'true'

done_out:

FunctionEnd


/** CheckBitnessMatch()
 *
 * Checks that the bitness of the ooRexx to be installed matches the bitness of
 * the ooRexx to be uninstalled.
 */
Function CheckBitnessMatch

  StrCpy $UserRequestAbort 'false'

  ${If} $RegVal_uninstallBitness != ""
    ${If} $RegVal_uninstallBitness != ${CPU}
      MessageBox MB_YESNO \
        "WARNING.  You are installing the ${CPU} version of ooRexx.$\n\
        The installed version of ooRexx is the $RegVal_uninstallBitness version.$\n\
        Running the uninstaller from within the installer in this case$\n\
        is known to cause problems, and is not supported.$\n$\n\
        The previous version of ooRexx should be uninstalled separately.  To$\n\
        do this, halt this installation.  Run the uninstall program using$\n\
        the Control Panel, or the Start Menu item under the Open Object$\n\
        Rexx program group.  Then restart this installation program.$\n$\n\
        Do you wish to continue the installation knowing there may be$\n\
        problems with the install?" \
        /SD IDNO IDYES done_return
        StrCpy $UserRequestAbort 'true'
        done_return:
    ${EndIf}
  ${EndIf}

FunctionEnd


/** CheckForSpaces()
 *
 * This function checks for spaces in a string.  It is taken from the NSIS
 * examples provided on the NSIS site.
 *
 * It should be used this way:
 *
 * push <str>
 * call CheckForSpaces
 * pop $R0
 *
 * $R0 will contain the number of spaces.  When using the LogicLib, a check like
 * this can be done
 *
 * ${If} $R0 > 0
 *   <do something>
 * ${EndIf}
 *
 */
Function CheckForSpaces
   Exch $R0
   Push $R1
   Push $R2
   Push $R3

   StrCpy $R1 -1
   StrCpy $R3 $R0
   StrCpy $R0 0
   loop:
     StrCpy $R2 $R3 1 $R1
     IntOp $R1 $R1 - 1
     StrCmp $R2 "" done
     StrCmp $R2 " " 0 loop
     IntOp $R0 $R0 + 1
   Goto loop
   done:

   Pop $R3
   Pop $R2
   Pop $R1
   Exch $R0
FunctionEnd

/** AddToPathExt()
 *
 * Adds the file extension(s) associated with the ooRexx executables to PATHEXT.
 *
 * We upper case the extension so that it matches what is commonly seen on
 * Windows.
 *
 * @notes - This could be done for a single-user install, but remember that
 *          the user specific PATHEXT *replaces* the system wide PATHEXT, so
 *          we would need to read the system wide value and add the extension
 *          to it and then write it to the user specific PATHEXT.
 */
Function AddToPathExt

  ${If} $IsAdminUser == "false"  ; TODO fix this
    Return
  ${EndIf}

  ${StrTok} $0 $RegVal_rexxAssociation " " "0" "0"
  ${StrCase} $1 $0 "U"
  DetailPrint "Adding the $1 extension to PATHEXT"
  Push $1
  Push $IsAdminUser      ; should only be "true" at this point
  Push "PATHEXT"
  Call AddToPath

  ${StrTok} $0 $RegVal_rexxHideAssociation " " "0" "0"
  ${StrCase} $1 $0 "U"
  DetailPrint "Adding the $1 extension to PATHEXT"
  Push $1
  Push $IsAdminUser      ; should only be "true" at this point
  Push "PATHEXT"
  Call AddToPath

  ${StrTok} $0 $RegVal_rexxPawsAssociation " " "0" "0"
  ${StrCase} $1 $0 "U"
  DetailPrint "Adding the $1 extension to PATHEXT"
  Push $1
  Push $IsAdminUser      ; should only be "true" at this point
  Push "PATHEXT"
  Call AddToPath

FunctionEnd

/** CheckIsRxapiService()
 *
 * Determines if rxapi is installed as a service.  On return the variable
 * RxapiIsService will be set to either 'true' or 'false'
 *
 */
Function CheckIsRxapiService
  services::IsServiceInstalled 'RXAPI'
  Pop $R0

  ${If} $R0 == 'Yes'
    StrCpy $RxapiIsService 'true'
  ${else}
    StrCpy $RxapiIsService 'false'
  ${EndIf}
FunctionEnd

/** CheckIsRxapirunning()
 *
 * Determines if a rxapi.exe process is running.  On return the variable
 * RxapiIsRunning is set to 'true', 'false' or 'unknown N' where N is an error
 * return code.
 *
 * TODO still need to test on Vista / Windows 7
 *
 */
Function CheckIsRxapiRunning
  ${If} $RxapiIsService == 'true'
    services::IsServiceRunning 'RXAPI'
    Pop $R0
    ${If} $R0 == 'Yes'
      StrCpy $RxapiIsRunning 'true'
    ${else}
      StrCpy $RxapiIsRunning 'false'
    ${EndIf}
  ${else}
    ooRexxProcess::findProcess "rxapi.exe"
    Pop $R0
    DetailPrint "ooRexxProcess::findProcess rc: $R0"
    ${If} $R0 == '0'
      StrCpy $RxapiIsRunning 'true'
    ${elseif} $R0 == '1'
      StrCpy $RxapiIsRunning 'false'
    ${else}
      StrCpy $RxapiIsRunning 'unknown $R0'
    ${EndIf}
  ${EndIf}
FunctionEnd

/** StopRxapi()
 *
 * Stop the rxapi.exe process.
 *
 * If rxapi is installed as a service, the stop command should stop it.
 * Otherwise, we use killProcess.
 *
 * On return top of stack will contain 'Ok' for success or 'Error'.  If there
 * was an error top of stack minus 1 will contain the error code from
 * ooRexx::killProcess.
 *
 * @remarks  There was a problem I was having with CheckisRxapiRunning saying
 *           rxapi was running when it actually was not.
 *
 *           When a service is sent the stop command it may take some time for
 *           it to report its state to the service control manager.  In addition
 *           the state may first be changed to stop pending.  In both of these
 *           cases CheckIsRxapirunning would report that rxapi is running.  So,
 *           a .3 sleep is added, which hopefully fixes the problem.
 */
Function StopRxapi

  ${If} $RxapiIsService == 'true'
    Services::SendServiceCommand 'stop' 'RXAPI'
    Pop $R0
    Sleep 300
  ${else}
    ooRexxProcess::killProcess 'rxapi'
    Pop $R0
  ${EndIf}

  Call CheckIsRxapiRunning
  ${If} $RxapiIsRunning == 'false'
    Push 'Ok'
    return
  ${EndIf}

  ; Still running, try one more time, it may be that the service has a stop
  ; pending.  Otherwise, this is probably a waste of time.  But, we will capture
  ; the error code for debugging.  Note that if the return from killProcess is
  ; 1, then the process was not found, so it is not running.  See the @remarks
  ; above.
  ooRexxProcess::killProcess 'rxapi'
  Pop $R0
  ${If} $R0 == 0
  ${orif} $R0 == 1
    Push 'Ok'
  ${else}
    Push $R0
    Push 'Error'
  ${EndIf}
FunctionEnd
