Dynamically create and delete directories: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
mNo edit summary
Line 5: Line 5:
These macros allow you to remove exactly those directories in the uninstaller which were created by the installer. So already existing directories (and non-empty ones) won't be removed on uninstall.
These macros allow you to remove exactly those directories in the uninstaller which were created by the installer. So already existing directories (and non-empty ones) won't be removed on uninstall.


(Courtesy of [http://stefan.bertels.org/ stefan.bertels.org])
Provided "as is" by [http://stefan.bertels.org/ stefan.bertels.org].
Use on your own risk.
Please [http://stefan.bertels.org/ report any bugs here].


== The Script ==
== The Script ==

Revision as of 08:50, 12 August 2005

Author: StB (talk, contrib)


Description

These macros allow you to remove exactly those directories in the uninstaller which were created by the installer. So already existing directories (and non-empty ones) won't be removed on uninstall.

Provided "as is" by stefan.bertels.org. Use on your own risk. Please report any bugs here.

The Script

; split "c:\test" into "c:" and "\test"
; split "\\server\share\test\test" into "\\server\share" and "\test\test"
; split other patterns into "" and "PATH"
; the two parts will be pushed on the stack
; get parts with Pop $drive and Pop $folder
!macro SplitPath PATH
  ; ATTENTION: USE ON YOUR OWN RISK!
  ; Please report bugs here: http://stefan.bertels.org/
  !define Index_SplitPath 'SplitPath_${__LINE__}'
  Push $R0
  StrCpy $R0 "${PATH}" ; $R0 contains PATH
  Push $R1
  Push $R2 ; number of the first "\" of folder part
  Push $R3
  Push $R4
 
  ; check for path type (c:\test or \\server\share\test)
  StrCpy $R2 $R0 2 0
  StrCmp $R2 "\\" 0 ${Index_SplitPath}-nounc
  StrCpy $R2 3
  StrLen $R1 $R0
  StrCpy $R4 -1
${Index_SplitPath}-loop:
  IntOp $R4 $R4 + 1
  IntCmp $R4 $R1 ${Index_SplitPath}-end
  StrCpy $R3 $R0 1 $R4
  StrCmp $R3 "\" 0 ${Index_SplitPath}-loop
  IntCmp $R2 0 ${Index_SplitPath}-split
  IntOp $R2 $R2 - 1
  Goto ${Index_SplitPath}-loop
${Index_SplitPath}-split:
  StrCpy $R1 $R0 "" $R4
  StrCpy $R0 $R0 $R4
  Goto ${Index_SplitPath}-finish
${Index_SplitPath}-end:
  StrCpy $R1 ""
  Goto ${Index_SplitPath}-finish
 
${Index_SplitPath}-nounc:
  StrCpy $R2 $R0 1 1
  StrCmp $R2 ":" 0 ${Index_SplitPath}-fallback
  StrCpy $R1 $R0 "" 2
  StrCpy $R0 $R0 2
  Goto ${Index_SplitPath}-finish
 
${Index_SplitPath}-fallback:
  StrCpy $R1 $R0
  StrCpy $R0 ""
${Index_SplitPath}-finish:
  Pop $R4
  Pop $R3
  Pop $R2
  Exch $R1 ; folder part
  Exch
  Exch $R0 ; drive part
  !undef Index_SplitPath
!macroend
 
; mkdir DIRECTORY and return the part which already existed (BASEDIR)
!macro MakeDirBase DIRECTORY
  ; ATTENTION: USE ON YOUR OWN RISK!
  ; Please report bugs here: http://stefan.bertels.org/
  !define Index_MakeDirBase 'MakeDirBase_${__LINE__}'
  Push $R0
  StrCpy $R0 "${DIRECTORY}" ; $R0 contains DIRECTORY
  Push $R1 ; $R1 is tmp path (increasing)
  Push $R2 ; number of "\" to ignore (1 for c:\, 4 for \\server\share\)
  Push $R3 ; pos
  Push $R4 ; len
  Push $R5 ; tmp char
  Push $R6 ; BASEDIR (return value)
  ; save outdir
  Push $OUTDIR
 
  !insertmacro GetCleanDir $R0
  Pop $R0
  !insertmacro SplitPath $R0
  Pop $R1 ; drive
  Pop $R2 ; folder
  StrCmp $R1 "" ${Index_MakeDirBase}-fallback ; ohne Laufwerk/UNC?
  StrCpy $R3 $R2 1 0
  StrCmp $R3 "\" 0 ${Index_MakeDirBase}-fallback ; relativ?
 
  StrCpy $R3 0
  StrCpy $R1 "$R1\"
  StrCpy $R6 $R1
  StrLen $R4 $R2
${Index_MakeDirBase}-loop:
  IntOp $R3 $R3 + 1
  IntCmp $R4 $R3 ${Index_MakeDirBase}-exists ; end of R0
  StrCpy $R5 $R2 1 $R3 ; get next char
  StrCpy $R1 "$R1$R5" ; add another char
  StrCmp $R5 "\" 0 ${Index_MakeDirBase}-loop
  ; debug  MessageBox MB_OK "check $R1"
  IfFileExists "$R1*.*" 0 ${Index_MakeDirBase}-mkdir
  StrCpy $R6 $R1
  Goto ${Index_MakeDirBase}-loop
${Index_MakeDirBase}-mkdir:
  ; debug  MessageBox MB_OK "mkdir $R0"
  SetOutPath $R0
  Goto ${Index_MakeDirBase}-finish
${Index_MakeDirBase}-exists:
  ;  debug MessageBox MB_OK "exists $R0"
  StrCpy $R6 $R0
  Goto ${Index_MakeDirBase}-finish
 
${Index_MakeDirBase}-fallback:
  ; debug MessageBox MB_OK "fallback"
  SetOutPath $R0
  !insertmacro GetCleanParentDir $R0
  Pop $R6
 
${Index_MakeDirBase}-finish:
  ; restore outdir
  Pop $OUTDIR
 
  StrCpy $R0 $R6
  Pop $R6
  Pop $R5
  Pop $R4
  Pop $R3
  Pop $R2
  Pop $R1
  Exch $R0
  !undef Index_MakeDirBase
!macroend
 
; rmdir DIRECTORY and all parents (if empty) up to BASEDIR (leave BASEDIR there)
!macro RemoveDirBase DIRECTORY BASEDIR
  ; ATTENTION: USE ON YOUR OWN RISK!
  ; Please report bugs here: http://stefan.bertels.org/
  !define Index_RemoveDirBase 'RemoveDirBase_${__LINE__}'
  Push ${DIRECTORY}
  Push ${BASEDIR}
  Push $R1
  Exch
  Pop $R1 ; $R1 contains BASEDIR
  Push $R0
  Exch 2
  Pop $R0 ; $0R contains DIRECTORY
  ; stack order: TOP => old $R1 => old $R0
  Push $R2
  Push $R3
  Push $OUTDIR
 
  !insertmacro GetCleanDir $R0
  Pop $R0
 
  ; basedir vorhanden?
  StrCmp $R1 "" ${Index_RemoveDirBase}-fallback
 
  ; basedir teil von DIRECTORY?
  StrLen $R2 $R1
  StrCpy $R3 $R0 $R2
  StrCmp $R1 $R3 0 ${Index_RemoveDirBase}-fallback ; is basedir the beginning of directory?
 
  ; außerdem muss BASEDIR mindestens (drive) enthalten
  !insertmacro SplitPath $R1
  Pop $R2  ; drive part
  Pop $R3  ; folder part
  StrCmp $R2 "" ${Index_RemoveDirBase}-fallback
  ; basedir is ok
 
${Index_RemoveDirBase}-loop:
  StrCmp $R0 $R1 ${Index_RemoveDirBase}-finish
  !insertmacro GetCleanParentDir $R0
  Pop $R2
  StrCmp $R2 $R0 ${Index_RemoveDirBase}-finish ; zur Sicherheit (kann eigentlich nicht auftreten)
  SetOutPath $R2
  RmDir $R0
  StrCpy $R0 $R2
  goto ${Index_RemoveDirBase}-loop
 
${Index_RemoveDirBase}-fallback:
  !insertmacro GetCleanParentDir $R0
  Pop $R1
  SetOutPath $R1
  RmDir $R0
 
${Index_RemoveDirBase}-finish:
  Pop $OUTDIR
  Pop $R3
  POp $R2
  Pop $R1
  Pop $R0
  !undef Index_RemoveDirBase
!macroend

Usage

Installer code:

  !insertmacro MakeDirBase $INSTDIR
  Pop $0
  WriteRegStr HKLM "...your_regkey_path..." "BasePath" "$0"

Uninstaller code:

  ReadRegStr $0 HKLM "...your_regkey_path..." "BasePath"
  !insertmacro RemoveDirBase "$INSTDIR" $0