Uninstall only installed files: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
Line 24: Line 24:
* Uninstaller now deletes itself and $INSTDIR
* Uninstaller now deletes itself and $INSTDIR
- mark
- mark


----
----
Line 31: Line 30:
* Removed Delete instruction to delete the uninstaller and added ${WriteUninstaller} instead.
* Removed Delete instruction to delete the uninstaller and added ${WriteUninstaller} instead.
* RMDir $INSDIR was repeated from last update.
* RMDir $INSDIR was repeated from last update.
- Afrow UK


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

Revision as of 19:31, 27 April 2007

Author: Afrow UK (talk, contrib)


Description

This code was written for Rookie12 a long while back. So many people have asked the same question since, so I thought that it was a good idea to put it up on here.

Entire script updated 12th May 2006

  • Added functions for AddItem, CopyFiles and Rename.
  • RMDir /r removed.
  • Log file now read in reverse order.

-Stu


Script updated 28 Sep 2006

  • Fix issue where uninstall.log is not created if $INSTDIR doesn't already exist
  • Fix infinite loop on uninstall - "last" line (actually first line) of uninstall.log is read over and over again

- Anonymoose


Script updated 08 Nov 2006

  • Uninstaller now deletes itself and $INSTDIR

- mark


Script updated 27 April 2007

  • Removed Delete instruction to delete the uninstaller and added ${WriteUninstaller} instead.
  • RMDir $INSDIR was repeated from last update.

- Afrow UK

The Script

This goes before all your own sections in your script...

!define UninstLog "uninstall.log"
Var UninstLog
 
; Uninstall log file missing.
LangString UninstLogMissing ${LANG_ENGLISH} "${UninstLog} not found!$\r$\nUninstallation cannot proceed!"
 
; AddItem macro
!macro AddItem Path
 FileWrite $UninstLog "${Path}$\r$\n"
!macroend
!define AddItem "!insertmacro AddItem"
 
; File macro
!macro File FilePath FileName
 IfFileExists "$OUTDIR\${FileName}" +2
  FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n"
 File "${FilePath}${FileName}"
!macroend
!define File "!insertmacro File"
 
; Copy files macro
!macro CopyFiles SourcePath DestPath
 IfFileExists "${DestPath}" +2
  FileWrite $UninstLog "${DestPath}$\r$\n"
 CopyFiles "${SourcePath}" "${DestPath}"
!macroend
!define CopyFiles "!insertmacro CopyFiles"
 
; Rename macro
!macro Rename SourcePath DestPath
 IfFileExists "${DestPath}" +2
  FileWrite $UninstLog "${DestPath}$\r$\n"
 Rename "${SourcePath}" "${DestPath}"
!macroend
!define Rename "!insertmacro Rename"
 
; CreateDirectory macro
!macro CreateDirectory Path
 CreateDirectory "${Path}"
 FileWrite $UninstLog "${Path}$\r$\n"
!macroend
!define CreateDirectory "!insertmacro CreateDirectory"
 
; SetOutPath macro
!macro SetOutPath Path
 SetOutPath "${Path}"
 FileWrite $UninstLog "${Path}$\r$\n"
!macroend
!define SetOutPath "!insertmacro SetOutPath"
 
; WriteUninstaller macro
!macro WriteUninstaller Path
 WriteUninstaller "${Path}"
 FileWrite $UninstLog "${Path}$\r$\n"
!macroend
!define SetOutPath "!insertmacro SetOutPath"
 
Section -openlogfile
 CreateDirectory "$INSTDIR"
 IfFileExists "$INSTDIR\${UninstLog}" +3
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" w
 Goto +4
  SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" a
  FileSeek $UninstLog 0 END
SectionEnd

Your own sections need to be placed here in your script.
Instead of using SetOutPath, CreateDirectory, File, CopyFiles and Rename instructions in your sections, use ${SetOutPath}, ${CreateDirectory}, ${File}, ${CopyFiles} and ${Rename} instead.

When using ${SetOutPath} to create more than one upper level directory, e.g.:
${SetOutPath} "$INSTDIR\dir1\dir2\dir3", you need to add entries for each lower level directory for them all to be deleted:
${AddItem} "$INSTDIR\dir1"
${AddItem} "$INSTDIR\dir1\dir2"
${SetOutPath} "$INSTDIR\dir1\dir2\dir3"

This is an example of what your sections may now look like...

Section "Install Main"
SectionIn RO
 
 ${SetOutPath} $INSTDIR
 ${WriteUninstaller} "uninstall.exe"
 ${File} "dir1\" "file1.ext"
 ${File} "dir1\" "file2.ext"
 ${File} "dir1\" "file3.ext"
 
SectionEnd
 
Section "Install Other"
 
 ${AddItem} "$INSTDIR\Other"
 ${SetOutPath} "$INSTDIR\Other\Temp"
 ${File} "dir2\" "file4.ext"
 ${File} "dir2\" "file5.ext"
 ${File} "dir2\" "file6.ext"
 
SectionEnd
 
Section "Copy Files & Rename"
 
 ${CreateDirectory} "$INSTDIR\backup"
 ${CopyFiles} "$INSTDIR\file1.ext" "$INSTDIR\backup\file1.ext"
 ${Rename} "$INSTDIR\file2.ext" "$INSTDIR\file1.ext"
 
SectionEnd

This comes after all your own sections in your script...

Section -closelogfile
 FileClose $UninstLog
 SetFileAttributes "$INSTDIR\${UninstLog}" READONLY|SYSTEM|HIDDEN
SectionEnd
 
Section Uninstall
 
 ; Can't uninstall if uninstall log is missing!
 IfFileExists "$INSTDIR\${UninstLog}" +3
  MessageBox MB_OK|MB_ICONSTOP "$(UninstLogMissing)"
   Abort
 
 Push $R0
 Push $R1
 Push $R2
 SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
 FileOpen $UninstLog "$INSTDIR\${UninstLog}" r
 StrCpy $R1 0
 
 GetLineCount:
  ClearErrors
   FileRead $UninstLog $R0
   IntOp $R1 $R1 + 1
   IfErrors 0 GetLineCount
 
 LoopRead:
  FileSeek $UninstLog 0 SET
  StrCpy $R2 0
  FindLine:
   FileRead $UninstLog $R0
   IntOp $R2 $R2 + 1
   StrCmp $R1 $R2 0 FindLine
 
   StrCpy $R0 $R0 -2
   IfFileExists "$R0\*.*" 0 +3
    RMDir $R0  #is dir
   Goto +3
   IfFileExists $R0 0 +2
    Delete $R0 #is file
 
  IntOp $R1 $R1 - 1
  StrCmp $R1 0 LoopDone
  Goto LoopRead
 LoopDone:
 FileClose $UninstLog
 Delete "$INSTDIR\${UninstLog}"
 RMDir "$INSTDIR"
 Pop $R2
 Pop $R1
 Pop $R0
SectionEnd

-Stu