Add/Remove Functionality

From NSIS Wiki

Author: THRaSH (talk, contrib)

The Script

This example creates a folder on Window desktop with subfolders "Component One", "Component Two", etc. according to changes you made on the components page.

Compile this example and run it for multiple times each time changing options on the components page to see the results.

Please mail me to if you know how to improve this.

How to use this in your installer:

  1. Copy and paste Add/Remove system macros to the beginning of your script or to include file.
  2. Copy and paste Add/Remove callback functions right before uninstall section. Ensure you specified section index output constants in Section commands for each optional section.
  3. List your optional sections in the SectionList macro. Use following format for each section (replace section_index with the constant name you specified in Section command):
     !insertmacro "${MacroName}" "section_index"
  4. Write Remove_${section_index} macro after each optional section. This macro must describe section deletion.

Here is code of example installer implementing add/remove functionality:

;--- Add/Remove system macros: ---
; (You may place them to include file)
Var AR_SecFlags
Var AR_RegFlags
!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.
  ;Reading component status from registry
  ReadRegDWORD $AR_RegFlags HKLM \
    "${REG_UNINSTALL}\Components\${SecName}" "Installed"
  IfErrors "default_${SecName}"
    ;Status will stay default if registry value not found
    ;(component was never installed)
  IntOp $AR_RegFlags $AR_RegFlags & 0x0001  ;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
  ;Writing modified flags
  SectionSetFlags ${${SecName}} $AR_SecFlags
!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 & 0x0001
  IntCmp $AR_SecFlags 1 "leave_${SecName}"
    ;Section is not selected:
    ;Calling Section uninstall macro and writing zero installed flag
    !insertmacro "Remove_${${SecName}}"
    WriteRegDWORD HKLM "${REG_UNINSTALL}\Components\${SecName}" \
  "Installed" 0
    Goto "exit_${SecName}"
    ;Section is selected:
    WriteRegDWORD HKLM "${REG_UNINSTALL}\Components\${SecName}" \
  "Installed" 1
!macro RemoveSection 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}}"
;--- End of Add/Remove macros ---
;  This constant specifies the installer file name.
!define InstFile "AddRemove.exe"
OutFile "${InstFile}"
;  This constant specifies Windows uninstall key for your application.
!define REG_UNINSTALL "Software\Microsoft\Windows\CurrentVersion\Uninstall\
InstallDir "$DESKTOP\AddRemove Example"
Name "Add/Remove Example 1.0"
ComponentText "Check the components you want to add and uncheck \
the components you want to remove:"
ShowInstDetails show
ShowUnInstDetails show
Section "Required Section"
SectionIn RO
  ;This section is required. It can't be removed.
  CreateDirectory $INSTDIR
  WriteUninstaller "$INSTDIR\Uninstall.exe"
;Writing uninstall info to registry:
  WriteRegStr HKLM "${REG_UNINSTALL}" "DisplayName" "Add/Remove Example"
  WriteRegStr HKLM "${REG_UNINSTALL}" "DisplayIcon" "$INSTDIR\Uninstall.exe"
  WriteRegStr HKLM "${REG_UNINSTALL}" "DisplayVersion" "1.0"
  WriteRegStr HKLM "${REG_UNINSTALL}" "Publisher" "THRaSH"
  WriteRegStr HKLM "${REG_UNINSTALL}" "InstallSource" "$EXEDIR\"
  ;Under WinXP this creates two separate buttons: "Modify" and "Remove".
  ;"Modify" will run installer and "Remove" will run uninstaller.
  WriteRegDWord HKLM "${REG_UNINSTALL}" "NoModify" 0
  WriteRegDWord HKLM "${REG_UNINSTALL}" "NoRepair" 0
  WriteRegStr HKLM "${REG_UNINSTALL}" "UninstallString" \
  WriteRegStr HKLM "${REG_UNINSTALL}" "ModifyPath" '"$EXEDIR\${InstFile}"'
Section "Component One (selected by default)" sec_One
  ;Installs component one
  ;By default this section is selected
  DetailPrint "*** Adding Component One..."
  CreateDirectory "$INSTDIR\Component One"
!macro Remove_${sec_One}
  ;Removes component one
  DetailPrint "*** Removing Component One..."
  RMDir /r "$INSTDIR\Component One"
Section /o "Component Two (unselected by default)" sec_Two
  ;Installs component two
  ;By default this section is not selected
  DetailPrint "*** Adding Component Two..."
  CreateDirectory "$INSTDIR\Component Two"
!macro Remove_${sec_Two}
  ;Removes component two
  DetailPrint "*** Removing Component Two..."
  RMDir /r "$INSTDIR\Component Two"
Section /o "Component Three (unselected by default)" sec_Three
  ;Installs component three
  ;By default this section is not selected
  DetailPrint "*** Adding Component Three..."
  CreateDirectory "$INSTDIR\Component Three"
!macro Remove_${sec_Three}
  ;Removes component three
  DetailPrint "*** Removing Component Three..."
  RMDir /r "$INSTDIR\Component Three"
;--- 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.
  !insertmacro "${MacroName}" "sec_One"
  !insertmacro "${MacroName}" "sec_Two"
  !insertmacro "${MacroName}" "sec_Three"
Function .onInit
  ;Reads components status for registry
  !insertmacro SectionList "InitSection"
Section -FinishComponents
  ;Removes unselected components and writes component status to registry
  !insertmacro SectionList "FinishSection"
Section -Post
  ;Showing the results
  ExecShell "open" "$INSTDIR"
;--- End of Add/Remove callback functions ---
Section Uninstall
  ;First removes all optional components
  !insertmacro SectionList "RemoveSection"
  ;Removes directory and registry key:
  DeleteRegKey HKLM "${REG_UNINSTALL}"
Personal tools