Useful InstallOptions and MUI macros: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
(→‎sample.ini: Changed NumFields from 16 to 15. It would not load in HM NIS Edit otherwise)
 
(One intermediate revision by one other user not shown)
(No difference)

Latest revision as of 18:12, 17 May 2012

Author: bholliger (talk, contrib)


Description

I created some macros that are useful for some InstallOptions tasks. Feel free to use and/or add your own macros as well. I hope they are useful.

General tips and hints for InstallOptions

Due to the fact that the field numbers define the tab-order this might change after adding another element to the dialog. Therefore I recommend using constants that hold the field names in a single location. This improves the general readability of the code as well.

;----------------------
;defines for Dialog 1 - sample.ini
 
  !define DIALOG1 "sample.ini"
 
  !define CHK_BLUE "Field 2"
  !define CHK_RED "Field 3"
  !define CHK_GREEN "Field 4"
  !define CHK_BROWN "Field 5"
  !define CHK_PROXYSETTINGS "Field 6"
  !define GRP_PROXYOPTIONS "Field 7"
  !define LBL_IPADDRESS "Field 8"
  !define TXT_IPADDRESS "Field 9"
  !define LBL_PORT1 "Field 10"
  !define TXT_PORT1 "Field 11"
  !define CHK_ENCRYPTION "Field 12"
  !define DRQ_NSISPATH "Field 14"
  !define CMD_AUTODETECTNSISPATH "Field 15"

Macro: GROUPCONTROLS

Activate a group of controls according to another control like a checkbox.

; Activate a group of controls, depending on the state of one control
; 
; Usage:
; 
; eg. !insertmacro GROUPCONTROLS "${DIALOG1}" "${CHK_PROXYSETTINGS}" 
; "${LBL_IPADDRESS}|${TXT_IPADDRESS}|${LBL_PORT1}|${TXT_PORT1}|${CHK_ENCRYPTION}"
; FILE:          INI-file in $pluginsdir
; SOURCECONTROL: RadioButton, Checkbox
; CONTROLGROUP:  pipe delimited list of controls; ${BUTTON1}|${CHECKBOX}|${TEXTFIELD}
;
; Requires:
;
; !include "WordFunc.nsh"
; !insertmacro WordReplace
; !insertmacro WordFind
;
!macro GROUPCONTROLS FILE SOURCECONTROL CONTROLGROUP
  Push $R0 ;holds element
  Push $R1 ;counter
  Push $R2 ;state of the control
  Push $R3 ;flags of the control / hwnd of the control
 
  !insertmacro MUI_INSTALLOPTIONS_READ $R2 "${FILE}" "${SOURCECONTROL}" "State"
 
  StrCpy $R1 1
  ${Do}
    ClearErrors
    ${WordFind} "${CONTROLGROUP}" "|" "E+$R1" $R0
 
    ${If} ${Errors}
    ${OrIf} $R0 == ""
      ${ExitDo}
    ${EndIf}
 
    ; Put state change in flags of element as well
    !insertmacro MUI_INSTALLOPTIONS_READ $R3 "${FILE}" "$R0" "Flags"
    ${If} "$R2" == "1"
      ${WordReplace} $R3 "DISABLED" "" "+" $R3
       ${WordReplace} $R3 "||" "|" "+" $R3
      !insertmacro MUI_INSTALLOPTIONS_WRITE "${FILE}" "$R0" "Flags" $R3
    ${Else}
      !insertmacro MUI_INSTALLOPTIONS_WRITE "${FILE}" "$R0" "Flags" "$R3|DISABLED"
    ${EndIf}
 
    !insertmacro MUI_INSTALLOPTIONS_READ $R3 "${FILE}" "$R0" "HWND"
    EnableWindow $R3 $R2
 
    IntOp $R1 $R1 + 1
  ${Loop}
 
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
 
!macroend

Macro: CHANGETEXTFIELD

Change the content of a textfield and write it to ini file. Ideal for autodetect purposes.

;change text field and put value in ini file
; 
; Usage:
;
;  !insertmacro CHANGETEXTFIELD "${DIALOG1}" "${DRQ_NSISPATH}" $tmp
;
; FILE:    INI-file in $pluginsdir
; ELEMENT: name of the control
; VALUE:   value that should appear in control
;
!macro CHANGETEXTFIELD FILE ELEMENT VALUE
  Push $R0 ; holds value
  !insertmacro MUI_INSTALLOPTIONS_WRITE ${VALUE} "${FILE}" "${ELEMENT}" "State"
  !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${FILE}" "${ELEMENT}" "HWND"
  SendMessage $R0 ${WM_SETTEXT} 0 "STR:${VALUE}"
  Pop $R0
!macroend

Macro: CHECKBOXCHECKER

Counts the number of activated controls and displays an error message if there are not enough controls selected. Select 3 or 4 out of 6.

; checks a group of checkboxes and counts how many of them
; are activated.
;
; Usage:
;
; Create a langstring containing an error message
; eg. LangString TEXT_LIMITATIONSEXEEDED ${LANG_ENGLISH} "Choose either two or three colours!"
;
; eg. !insertmacro CHECKBOXCHECKER "${DIALOG1}" "${CHK_BLUE}|${CHK_RED}|${CHK_GREEN}|${CHK_BROWN}" 2 3
;
; FILE:          INI-file in $pluginsdir
; CONTROLGROUP:  pipe delimited list of controls; ${BUTTON1}|${CHECKBOX}|${TEXTFIELD}
; MIN/MAX:       at least ${MIN} and no more than ${MAX} controls must be in activated state
;
; Requires:
;
; !include "WordFunc.nsh"
; !insertmacro WordFind
;
!macro CHECKBOXCHECKER FILE CONTROLGROUP MIN MAX
 
  Push $R0 ;holds element
  Push $R1 ;counter
  Push $R2 ;count activated elements
  Push $R3 ;state of the control
 
  StrCpy $R1 1
  StrCpy $R2 0
  ${Do}
    ClearErrors
    ${WordFind} "${CONTROLGROUP}" "|" "E+$R1" $R0
 
    ${If} ${Errors}
    ${OrIf} $R0 == ""
      ${ExitDo}
    ${EndIf}
 
    ; Put state change in flags of element as well
    !insertmacro MUI_INSTALLOPTIONS_READ $R3 "${FILE}" "$R0" "State"
    ${If} "$R3" == "1"
      IntOp $R2 $R2 + 1
    ${EndIf}
 
    IntOp $R1 $R1 + 1
  ${Loop}
 
  ${If} $R2 < ${MIN}
  ${OrIf} $R2 > ${MAX}
    MessageBox MB_OK|MB_ICONSTOP "$(TEXT_LIMITATIONSEXCEEDED)"
    Abort
  ${EndIf}
 
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
 
!macroend

Sample

Have a look at the sample.

;---------------------
;Include Modern UI
 
  !include "MUI.nsh"
  !include "LogicLib.nsh"
;----------------------
;defines for Dialog 1 - sample.ini
 
  !define DIALOG1 "sample.ini"
 
  !define CHK_BLUE "Field 2"
  !define CHK_RED "Field 3"
  !define CHK_GREEN "Field 4"
  !define CHK_BROWN "Field 5"
  !define CHK_PROXYSETTINGS "Field 6"
  !define GRP_PROXYOPTIONS "Field 7"
  !define LBL_IPADDRESS "Field 8"
  !define TXT_IPADDRESS "Field 9"
  !define LBL_PORT1 "Field 10"
  !define TXT_PORT1 "Field 11"
  !define CHK_ENCRYPTION "Field 12"
  !define DRQ_NSISPATH "Field 14"
  !define CMD_AUTODETECTNSISPATH "Field 15"
;--------------------------------
;General
 
  ;Name and file
  Name "MUI installation validation example"
  OutFile "test.exe"
 
  ;Default installation folder
  InstallDir "$PROGRAMFILES\MUI validate"
 
  ;Get installation folder from registry if available
  InstallDirRegKey HKCU "Software\MUI validate" ""
 
;--------------------------------
;Pages
 
  Page custom InitPage ValidatePage
  !insertmacro MUI_PAGE_DIRECTORY
  !insertmacro MUI_PAGE_INSTFILES
 
;--------------------------------
;Interface Settings
 
  !define MUI_ABORTWARNING
 
;--------------------------------
;Languages
 
  !insertmacro MUI_LANGUAGE "English"
 
;--------------------------------
;Reserve Files
 
  ;If you are using solid compression, files that are required before
  ;the actual installation should be stored first in the data block,
  ;because this will make your installer start faster.
 
  ReserveFile "sample.ini"
  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
 
;--------------------------------
;Variables
 
  Var "tmp"
 
!include "WordFunc.nsh"
!insertmacro WordReplace
!insertmacro WordFind
 
; Activate a group of controls, depending on the state of one control
; 
; Usage:
; 
; eg. !insertmacro GROUPCONTROLS "${DIALOG1}" "${CHK_PROXYSETTINGS}" "${LBL_IPADDRESS}|${TXT_IPADDRESS}|${LBL_PORT1}|${TXT_PORT1}|${CHK_ENCRYPTION}"
; FILE:          INI-file in $pluginsdir
; SOURCECONTROL: RadioButton, Checkbox
; CONTROLGROUP:  pipe delimited list of controls; ${BUTTON1}|${CHECKBOX}|${TEXTFIELD}
;
; Requires:
;
; !include "WordFunc.nsh"
; !insertmacro WordReplace
; !insertmacro WordFind
;
!macro GROUPCONTROLS FILE SOURCECONTROL CONTROLGROUP
  Push $R0 ;holds element
  Push $R1 ;counter
  Push $R2 ;state of the control
  Push $R3 ;flags of the control / hwnd of the control
 
  !insertmacro MUI_INSTALLOPTIONS_READ $R2 "${FILE}" "${SOURCECONTROL}" "State"
 
  StrCpy $R1 1
  ${Do}
    ClearErrors
    ${WordFind} "${CONTROLGROUP}" "|" "E+$R1" $R0
 
    ${If} ${Errors}
    ${OrIf} $R0 == ""
      ${ExitDo}
    ${EndIf}
 
    ; Put state change in flags of element as well
    !insertmacro MUI_INSTALLOPTIONS_READ $R3 "${FILE}" "$R0" "Flags"
    ${If} "$R2" == "1"
      ${WordReplace} $R3 "DISABLED" "" "+" $R3
       ${WordReplace} $R3 "||" "|" "+" $R3
      !insertmacro MUI_INSTALLOPTIONS_WRITE "${FILE}" "$R0" "Flags" $R3
    ${Else}
      !insertmacro MUI_INSTALLOPTIONS_WRITE "${FILE}" "$R0" "Flags" "$R3|DISABLED"
    ${EndIf}
 
    !insertmacro MUI_INSTALLOPTIONS_READ $R3 "${FILE}" "$R0" "HWND"
    EnableWindow $R3 $R2
 
    IntOp $R1 $R1 + 1
  ${Loop}
 
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
 
!macroend
 
;change text field and put value in ini file
; 
; Usage:
;
;  !insertmacro CHANGETEXTFIELD "${DIALOG1}" "${DRQ_NSISPATH}" $tmp
;
; FILE:    INI-file in $pluginsdir
; ELEMENT: name of the control
; VALUE:   value that should appear in control
;
!macro CHANGETEXTFIELD FILE ELEMENT VALUE
  Push $R0 ; holds value
  !insertmacro MUI_INSTALLOPTIONS_WRITE ${VALUE} "${FILE}" "${ELEMENT}" "State"
  !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${FILE}" "${ELEMENT}" "HWND"
  SendMessage $R0 ${WM_SETTEXT} 0 "STR:${VALUE}"
  Pop $R0
!macroend
 
; checks a group of checkboxes and counts how many of them
; are activated.
;
; Usage:
;
; Create a langstring containing an error message
; eg. LangString TEXT_LIMITATIONSEXEEDED ${LANG_ENGLISH} "Choose either two or three colours!"
;
; eg. !insertmacro CHECKBOXCHECKER "${DIALOG1}" "${CHK_BLUE}|${CHK_RED}|${CHK_GREEN}|${CHK_BROWN}" 2 3
;
; FILE:          INI-file in $pluginsdir
; CONTROLGROUP:  pipe delimited list of controls; ${BUTTON1}|${CHECKBOX}|${TEXTFIELD}
; MIN/MAX:       at least ${MIN} and no more than ${MAX} controls must be in activated state
;
; Requires:
;
; !include "WordFunc.nsh"
; !insertmacro WordFind
;
!macro CHECKBOXCHECKER FILE CONTROLGROUP MIN MAX
 
  Push $R0 ;holds element
  Push $R1 ;counter
  Push $R2 ;count activated elements
  Push $R3 ;state of the control
 
  StrCpy $R1 1
  StrCpy $R2 0
  ${Do}
    ClearErrors
    ${WordFind} "${CONTROLGROUP}" "|" "E+$R1" $R0
 
    ${If} ${Errors}
    ${OrIf} $R0 == ""
      ${ExitDo}
    ${EndIf}
 
    ; Put state change in flags of element as well
    !insertmacro MUI_INSTALLOPTIONS_READ $R3 "${FILE}" "$R0" "State"
    ${If} "$R3" == "1"
      IntOp $R2 $R2 + 1
    ${EndIf}
 
    IntOp $R1 $R1 + 1
  ${Loop}
 
  ${If} $R2 < ${MIN}
  ${OrIf} $R2 > ${MAX}
    MessageBox MB_OK|MB_ICONSTOP "$(TEXT_LIMITATIONSEXCEEDED)"
    Abort
  ${EndIf}
 
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
 
!macroend
 
;--------------------------------
;Installer Sections
 
Section "Dummy Section" SecDummy
 
  SetOutPath "$INSTDIR"
 
  ;ADD YOUR OWN FILES HERE...
 
SectionEnd
 
;--------------------------------
;Installer Functions
 
Function .onInit
 
;  !insertmacro MUI_LANGDLL_DISPLAY
 
FunctionEnd
 
LangString TEXT_IO_TITLE ${LANG_ENGLISH} "Test page"
LangString TEXT_IO_SUBTITLE ${LANG_ENGLISH} "Test some things"
LangString TEXT_LIMITATIONSEXCEEDED ${LANG_ENGLISH} "Choose either two or three colours!"
 
Function InitPage
 
  ;Extract InstallOptions INI files
  !insertmacro MUI_INSTALLOPTIONS_EXTRACT "${DIALOG1}"
 
  !insertmacro MUI_HEADER_TEXT "$(TEXT_IO_TITLE)" "$(TEXT_IO_SUBTITLE)"
  !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "${DIALOG1}"
  !insertmacro GROUPCONTROLS "${DIALOG1}" "${CHK_PROXYSETTINGS}" "${LBL_IPADDRESS}|${TXT_IPADDRESS}|${LBL_PORT1}|${TXT_PORT1}|${CHK_ENCRYPTION}"
  !insertmacro MUI_INSTALLOPTIONS_SHOW  
 
FunctionEnd
 
Function ValidatePage
  ; handle notify event of element
  !insertmacro MUI_INSTALLOPTIONS_READ $tmp "${DIALOG1}" "Settings" "State"  
  ${Switch} "Field $tmp"
    ${Case} "${CHK_PROXYSETTINGS}"
      !insertmacro GROUPCONTROLS "${DIALOG1}" "${CHK_PROXYSETTINGS}" "${LBL_IPADDRESS}|${TXT_IPADDRESS}|${LBL_PORT1}|${TXT_PORT1}|${CHK_ENCRYPTION}"
      Abort
    ${Case} "${CMD_AUTODETECTNSISPATH}"
      ;read registry value and set text field
      ReadRegStr $tmp HKLM "Software\NSIS" ""
      !insertmacro CHANGETEXTFIELD "${DIALOG1}" "${DRQ_NSISPATH}" $tmp
      Abort      
  ${EndSwitch}
 
  ; check if 2 or 3 check boxes are activated
  !insertmacro CHECKBOXCHECKER "${DIALOG1}" "${CHK_BLUE}|${CHK_RED}|${CHK_GREEN}|${CHK_BROWN}" 2 3
 
  ;  check if checkbox is activated
  !insertmacro MUI_INSTALLOPTIONS_READ $tmp "${DIALOG1}" "${CHK_PROXYSETTINGS}" "State"  
  ${If} $tmp == 1
    Var /GLOBAL ip1
    Var /GLOBAL port1
 
    !insertmacro MUI_INSTALLOPTIONS_READ $ip1 "${DIALOG1}" "${TXT_IPADDRESS}" "State"
    Push "$ip1"
    Call ValidateIP
    ${If} ${Errors}
      MessageBox MB_ICONEXCLAMATION "IP not correct! $ip1"
      Abort
    ${EndIf}
 
    !insertmacro MUI_INSTALLOPTIONS_READ $port1 "${DIALOG1}" "${TXT_PORT1}" "State"
    ${If} $port1 < 1024
    ${OrIf} $port1 > 32768
      MessageBox MB_ICONEXCLAMATION "Port not valid!"
      Abort
    ${EndIf}
  ${EndIf}
 
  ; check for file in NSIS' path
  !insertmacro MUI_INSTALLOPTIONS_READ $tmp "${DIALOG1}" "${DRQ_NSISPATH}" "State"
  ${Unless} ${FileExists} "$tmp\makensis.exe"
    MessageBox MB_OK|MB_ICONEXCLAMATION "makensis.exe in NSIS path not found!"
    Abort
  ${EndIf}
 
  ; TODO: save values to ini file/registry...
 
FunctionEnd
 
; http://nsis.sourceforge.net/Validate_IP_function
!include WordFunc.nsh
 
!insertmacro WordFind
!insertmacro StrFilter
Function ValidateIP
 
  Exch $0
  Push $1
  Push $2
 
  ${StrFilter} $0 1 "." "" $1
  ${If} $0 != $1
    # invalid charcaters used
    #   example: a127.0.0.1
    Goto error
  ${EndIf}
 
  ${WordFind} $0 . "#" $1
  ${If} $1 != 4
    # wrong number of numbers
    #   example: 127.0.0.
    Goto error
  ${EndIf}
 
  ${WordFind} $0 . "*" $1
  ${If} $1 != 3
    # wrong number of dots
    #   example: 127.0.0.1.
    Goto error
  ${EndIf}
 
  ${For} $2 1 4
    ${WordFind} $0 . +$2 $1
 
    ${If} $1 > 255
    ${OrIf} $1 < 0
      # invalid number
      #   example: 500.0.0.1
      Goto error
    ${EndIf}
  ${Next}
 
  Pop $2
  Pop $1
  Pop $0
 
  ClearErrors
 
  Return
 
  error:
 
    Pop $2
    Pop $1
    Pop $0
 
    SetErrors
 
FunctionEnd

sample.ini

; Ini file generated by the HM NIS Edit IO designer.
[Settings]
NumFields=15
 
[Field 1]
Type=Groupbox
Text=Colour (choose 2 or 3)
Left=0
Right=112
Top=0
Bottom=56
 
[Field 2]
Type=CheckBox
Text=&Blue
Left=5
Right=80
Top=10
Bottom=20
State=0
 
[Field 3]
Type=CheckBox
Text=&Red
Left=5
Right=80
Top=20
Bottom=30
 
[Field 4]
Type=CheckBox
Text=&Green
Left=5
Right=80
Top=30
Bottom=40
 
[Field 5]
Type=CheckBox
Text=&Brown
Left=5
Right=79
Top=40
Bottom=49
 
[Field 6]
Type=Checkbox
Text=&Set proxy options (NOTIFY)
Flags=NOTIFY
Left=117
Right=225
Top=0
Bottom=10
 
[Field 7]
Type=Groupbox
Left=117
Right=-1
Top=10
Bottom=56
Text=Proxy options
 
[Field 8]
Type=Label
Text=&IP-Address:
Left=122
Right=165
Top=22
Bottom=30
 
[Field 9]
Type=Text
Left=122
Right=240
Top=30
Bottom=42
 
[Field 10]
Type=Label
Text=&Port:
Left=244
Right=264
Top=22
Bottom=30
 
[Field 11]
Type=Text
Left=244
Right=-10
Top=30
Bottom=42
 
[Field 12]
Type=Checkbox
Text=&Use encryption
Left=122
Right=187
Top=44
Bottom=54
 
[Field 13]
Type=Groupbox
Text=Set NSIS path or click autodetect
Left=117
Right=-1
Top=61
Bottom=116
 
[Field 14]
Type=DirRequest
Left=122
Right=-10
Top=77
Bottom=89
 
[Field 15]
Type=Button
Text=&Autodetect
Flags=NOTIFY
Left=245
Right=-10
Top=92
Bottom=106