Auto-uninstall old before installing new: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
m (Added category links.)
(Empty string protection)
 
(9 intermediate revisions by 8 users not shown)
Line 1: Line 1:
{|align=right
{{PageAuthor|Anders}}
|<small>Author: [[{{ns:2}}:codehistorian|codehistorian]] ([[{{ns:3}}:codehistorian|talk]], [[{{ns:-1}}:Contributions/codehistorian|contrib]])</small>
[[Category:Code Examples]]
|}
[[Category:Functions_%26_Macros]]
<br style="clear:both;">
This is a code snippet you can put into your .onInit function that will detect whether your software is already installed and, if so, allows the user to uninstall it first.


In the source below, we use the define ${PROGRAM_NAME} to be the name of the product as well as the name of the installer/uninstaller.  You can either define this define or search/replace it. If you name your uninstaller or registry location differently, you should change those strings accordingly.
This code can be used to uninstall a existing installation. The previous installation must also be a NSIS based install.


<highlight-nsis>
<highlight-nsis>
Function .onInit
RequestExecutionLevel User
InstallDir "$LocalAppData\Programs\NSISTest"
!define UninstId "NSISTest" ; You might want to use a GUID here
 
!include LogicLib.nsh


  ReadRegStr $R0 HKLM \
  "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" \
  "UninstallString"
  StrCmp $R0 "" done


  MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
!macro UninstallExisting exitcode uninstcommand
  "${PROGRAM_NAME} is already installed. $\n$\nClick `OK` to remove the \
Push `${uninstcommand}`
  previous version or `Cancel` to cancel this upgrade." \
Call UninstallExisting
  IDOK uninst
Pop ${exitcode}
  Abort
!macroend
 
Function UninstallExisting
;Run the uninstaller
Exch $1 ; uninstcommand
uninst:
Push $2 ; Uninstaller
  ClearErrors
Push $3 ; Len
  ExecWait '$R0 _?=$INSTDIR' ;Do not copy the uninstaller to a temp file
StrCpy $3 ""
StrCpy $2 $1 1
StrCmp $2 '"' qloop sloop
sloop:
StrCpy $2 $1 1 $3
IntOp $3 $3 + 1
StrCmp $2 "" +2
StrCmp $2 ' ' 0 sloop
IntOp $3 $3 - 1
Goto run
qloop:
StrCmp $3 "" 0 +2
StrCpy $1 $1 "" 1 ; Remove initial quote
IntOp $3 $3 + 1
StrCpy $2 $1 1 $3
StrCmp $2 "" +2
StrCmp $2 '"' 0 qloop
run:
StrCpy $2 $1 $3 ; Path to uninstaller
StrCpy $1 161 ; ERROR_BAD_PATHNAME
GetFullPathName $3 "$2\.." ; $InstDir
IfFileExists "$2" 0 +4
ExecWait '"$2" /S _?=$3' $1 ; This assumes the existing uninstaller is a NSIS uninstaller, other uninstallers don't support /S nor _?=
IntCmp $1 0 "" +2 +2 ; Don't delete the installer if it was aborted
Delete "$2" ; Delete the uninstaller
RMDir "$3" ; Try to delete $InstDir
RMDir "$3\.." ; (Optional) Try to delete the parent of $InstDir
Pop $3
Pop $2
Exch $1 ; exitcode
FunctionEnd


  IfErrors no_remove_uninstaller
    ;You can either use Delete /REBOOTOK in the uninstaller or add some code
    ;here to remove to remove the uninstaller. Use a registry key to check
    ;whether the user has chosen to uninstall. If you are using an uninstaller
    ;components page, make sure all sections are uninstalled.
  no_remove_uninstaller:
 
done:


Function .onInit
ReadRegStr $0 HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "UninstallString"
${If} $0 != ""
${AndIf} ${Cmd} `MessageBox MB_YESNO|MB_ICONQUESTION "Uninstall previous version?" /SD IDYES IDYES`
!insertmacro UninstallExisting $0 $0
${If} $0 <> 0
MessageBox MB_YESNO|MB_ICONSTOP "Failed to uninstall, continue anyway?" /SD IDYES IDYES +2
Abort
${EndIf}
${EndIf}
FunctionEnd
FunctionEnd
Page Directory
Page InstFiles
Section
SetOutPath $InstDir
File "/oname=$InstDir\App.exe" "${__FILE__}" ; Dummy file
WriteUninstaller "$InstDir\Uninst.exe"
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "DisplayName" "NSIS Test"
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "UninstallString" '"$InstDir\Uninst.exe"'
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "QuietUninstallString" '"$InstDir\Uninst.exe" /S'
SectionEnd
Section Uninstall
Delete "$InstDir\App.exe"
DeleteRegKey HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}"
Delete "$InstDir\Uninst.exe"
RMDir "$InstDir"
SectionEnd
</highlight-nsis>
</highlight-nsis>
[[{{ns:14}}:Windows Shell Integration Functions]]

Latest revision as of 13:45, 3 September 2019

Author: Anders (talk, contrib)


This code can be used to uninstall a existing installation. The previous installation must also be a NSIS based install.

RequestExecutionLevel User
InstallDir "$LocalAppData\Programs\NSISTest"
!define UninstId "NSISTest" ; You might want to use a GUID here
 
!include LogicLib.nsh
 
 
!macro UninstallExisting exitcode uninstcommand
Push `${uninstcommand}`
Call UninstallExisting
Pop ${exitcode}
!macroend
Function UninstallExisting
Exch $1 ; uninstcommand
Push $2 ; Uninstaller
Push $3 ; Len
StrCpy $3 ""
StrCpy $2 $1 1
StrCmp $2 '"' qloop sloop
sloop:
	StrCpy $2 $1 1 $3
	IntOp $3 $3 + 1
	StrCmp $2 "" +2
	StrCmp $2 ' ' 0 sloop
	IntOp $3 $3 - 1
	Goto run
qloop:
	StrCmp $3 "" 0 +2
	StrCpy $1 $1 "" 1 ; Remove initial quote
	IntOp $3 $3 + 1
	StrCpy $2 $1 1 $3
	StrCmp $2 "" +2
	StrCmp $2 '"' 0 qloop
run:
	StrCpy $2 $1 $3 ; Path to uninstaller
	StrCpy $1 161 ; ERROR_BAD_PATHNAME
	GetFullPathName $3 "$2\.." ; $InstDir
	IfFileExists "$2" 0 +4
	ExecWait '"$2" /S _?=$3' $1 ; This assumes the existing uninstaller is a NSIS uninstaller, other uninstallers don't support /S nor _?=
	IntCmp $1 0 "" +2 +2 ; Don't delete the installer if it was aborted
	Delete "$2" ; Delete the uninstaller
	RMDir "$3" ; Try to delete $InstDir
	RMDir "$3\.." ; (Optional) Try to delete the parent of $InstDir
Pop $3
Pop $2
Exch $1 ; exitcode
FunctionEnd
 
 
Function .onInit
ReadRegStr $0 HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "UninstallString"
${If} $0 != ""
${AndIf} ${Cmd} `MessageBox MB_YESNO|MB_ICONQUESTION "Uninstall previous version?" /SD IDYES IDYES`
	!insertmacro UninstallExisting $0 $0
	${If} $0 <> 0
		MessageBox MB_YESNO|MB_ICONSTOP "Failed to uninstall, continue anyway?" /SD IDYES IDYES +2
			Abort
	${EndIf}
${EndIf}
FunctionEnd
 
Page Directory
Page InstFiles
 
Section
SetOutPath $InstDir
File "/oname=$InstDir\App.exe" "${__FILE__}" ; Dummy file
WriteUninstaller "$InstDir\Uninst.exe"
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "DisplayName" "NSIS Test"
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "UninstallString" '"$InstDir\Uninst.exe"'
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "QuietUninstallString" '"$InstDir\Uninst.exe" /S'
SectionEnd
 
Section Uninstall
Delete "$InstDir\App.exe"
DeleteRegKey HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}"
Delete "$InstDir\Uninst.exe"
RMDir "$InstDir"
SectionEnd