Add/Remove Functionality: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
m (Grammar corrections)
 
(Undo (SPAM) revision 18803 by 77.79.235.138 (Talk))
 
(90 intermediate revisions by 53 users not shown)
Line 1: Line 1:
{{PageAuthor|THRaSH}}
{{PageAuthor|THRaSH}}
== Description ==
This example demonstrates how to implement Add/Remove functionality in the installer. It operates similarly to the MS Office installer.
Unlike a conventional NSIS installer it will not only install (upgrade) selected components but will also remove unselected components.
It is very easy to provide add/remove ability in your installer. You just need to add a "section uninstaller" macro after each optional section and paste or include Add/Remove system macros and callback functions in your script. (See detailed instruction below).
== How It Works ==
On initialization it restores components installed flags (if present) from registry and sets components status (checked / not checked) on the components page. If installed flag not found then the component status stays default settings (new installation).
At the end of installation it removes unchecked components using special Remove_... macro you add after each component section.
Note: Remove_... macros must not produce errors even if component does not actually installed.
Uninstaller still removes all of your software w/o an option. But now you can use Remove_... macros to remove optional components. So uninstall code becomes more simple and flexible.


== The Script ==
== The Script ==
Line 20: Line 8:
Please mail me to ts2001@hotbox.ru if you know how to improve this.
Please mail me to ts2001@hotbox.ru if you know how to improve this.


How to use this in your intaller:
How to use this in your installer:
# Copy and paste Add/Remove system macros to the beginning of your script or to include file.
# Copy and paste Add/Remove system macros to the beginning of your script or to include file.
# 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.
# 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.

Latest revision as of 22:11, 4 August 2010

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 ts2001@hotbox.ru 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.
 
  ClearErrors
  ;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
 
 "default_${SecName}:"
!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 & 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}"
 
 "leave_${SecName}:"
    ;Section is selected:
    WriteRegDWORD HKLM "${REG_UNINSTALL}\Components\${SecName}" \
  "Installed" 1
 
 "exit_${SecName}:"
!macroend
 
!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}}"
!macroend
;--- 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\
\AddRemoveExample"
 
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" \
'"$INSTDIR\Uninstall.exe"'
  WriteRegStr HKLM "${REG_UNINSTALL}" "ModifyPath" '"$EXEDIR\${InstFile}"'
SectionEnd
 
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"
SectionEnd
!macro Remove_${sec_One}
  ;Removes component one
  DetailPrint "*** Removing Component One..."
  RMDir /r "$INSTDIR\Component One"
!macroend
 
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"
SectionEnd
!macro Remove_${sec_Two}
  ;Removes component two
  DetailPrint "*** Removing Component Two..."
  RMDir /r "$INSTDIR\Component Two"
!macroend
 
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"
SectionEnd
!macro Remove_${sec_Three}
  ;Removes component three
  DetailPrint "*** Removing Component Three..."
  RMDir /r "$INSTDIR\Component Three"
!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.
 
  !insertmacro "${MacroName}" "sec_One"
  !insertmacro "${MacroName}" "sec_Two"
  !insertmacro "${MacroName}" "sec_Three"
!macroend
 
Function .onInit
  ;Reads components status for registry
  !insertmacro SectionList "InitSection"
FunctionEnd
 
Section -FinishComponents
  ;Removes unselected components and writes component status to registry
  !insertmacro SectionList "FinishSection"
SectionEnd
 
Section -Post
  ;Showing the results
  ExecShell "open" "$INSTDIR"
SectionEnd
;--- End of Add/Remove callback functions ---
 
 
Section Uninstall
  ;First removes all optional components
  !insertmacro SectionList "RemoveSection"
 
  ;Removes directory and registry key:
  RMDIR /r $INSTDIR
  DeleteRegKey HKLM "${REG_UNINSTALL}"
SectionEnd