Archive: Another ExecWait / Uninstaller


Another ExecWait / Uninstaller
Hi everyone
I've searched the forum and read about a dozen threads on this, still I just don't get it working properly.
Here's what I want my script to do:
It checks for old versions in .onInit then goes on to delete it (by using the uninstall.exe)
Here's the part of the .onInit (the variables all work fine)

---------------------------
ReadRegStr $R1 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString"
IfErrors +6 0
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DefButton1 "$(OldInstFound)" IDYES 0 IDNO +4
ClearErrors
ExecWait '"$R1" "_?=$TEMP"'
IfErrors 0 +2
MessageBox MB_OK|MB_ICONEXCLAMATION "$(OldInstNotRemoved)"
ClearErrors
------------------------------------

$R1 is not quoted before so it's not a double quote.
Now, the uninstaller runs fine, the ExecWait wait's for me. Problem is, the uninstaller.exe is not deleted, neither the Install-Dir is
Here's the part of Section Uninstall that's not working:

-------------------------------
Delete "$R0\uninst.exe"
setoutpath "$R1" ;$R1 is the parent directory
RMDir /r "$R0\Opera$8\LEO-Extension"
-------------------------------
If I'm calling uninst.exe it work's fine, just by copying via ?_=$TEMP doesn't allow me to delete the file and neither the directory.
I know I'm waiting for the uninstaller, but ain't I waiting for the *COPY* of the uninstaller? If not, how can I do both things - running and waiting for the uninstall and then deleting itself?
Thanks in advance

Martin


You should execute the uninstaller which is in the same folder as your software. The uninstaller copies itself to $TEMP and then runs from there, and deletes itself on its own.
Unless your files are installed in $TEMP you shouldn't be passing it _?=$TEMP because that's telling it to uninstall files in the $TEMP folder.

-Stu


Well, yes, I know that uninst.exe copies itself to $TEMP - but that's why Execwait *doesn't* wait for the uninstaller to complete the uninstall. It will continue with the setup immediately - which I don't want.
Now, if I DO use the _?=$TEMP string on the Execwait command, Execwait works just fine. It doesn't matter that I'm copying it to $TEMP manually because all the files that will be changed or deleted are referenced with a full path.
Now, let's say the Uninst.exe is written to C:\BLA during install. Some files of the install are in c:\BLA, some in c:\BLE.
$R1 = C:\BLA\uninst.exe
Now, with

Execwait '"$R1" _?$TEMP'

I'm copying the uninst.exe to the TEMP-Dir and starting it, right? Then why can't I delete c:\BLA\uninst.exe ? Why can't I RMDIR /r C:\BLA ? It does delete c:\BLE just fine.
If I'm calling the uninst.exe manually from C:\BLA everything is ok.

If I'm using Execwait "$R1" only, the installer will continue to run the setup without waiting for the uninst.exe to finish.
Very strange, very strange...
I'd appreciate any more tips :-)
Thanks

Martin


Are you sure $R1 points to $TEMP\uninst.exe? Check it with a MessageBox.


No, $R1 points to the location where the file "uninst.exe" was originally written. I thought that specifying _?$TEMP it is copied to the TEMP BEFORE it is executed and BEFORE it would copy itself there?
So do I have to copy (rename? or is there another way?) the uninst.exe manually to some other directory before calling it just so that Execwait will work? But Execwait still wouldn't work, since the uninst.exe would copy itself AGAIN so it can be deleted during uninstall process, right?
I simply don't get it - maybe I'm having blinders on or something...
Martin


Specifying _?=$INSTDIR on the command line simply sets the $INSTDIR for the uninstaller. If it's not specified, the uninstaller will copy itself to the temporary directory, execute that copy with _?=$INSTDIR and exit. What you need to do is copy and execute it yourself.


If I remember correctly, the makensis.nsi script has this very subject in it. The current nsis version checks for a nsis installation, if it finds an installation, it checks the version. If there is an older version, the installer will ask to uninstall or continue. Selecting uninstall will execute the uninstaller and wait for it to end. Then the installer continues. Have a look at the script and borrow some code from there.


This is my next try, still not working...

-----------------------------------------
MessageBox MB_OK "$INSTDIR"
ClearErrors
ReadRegStr $R1 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString"
IfErrors +8 0
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DefButton1 "$(OldInstFound)" IDYES 0 IDNO +7
ClearErrors
CopyFiles /SILENT "$R1" "$TEMP\uninst123.exe"
ExecWait '"$TEMP\uninst123.exe" "_?=$INSTDIR"'
IfErrors 0 +2
MessageBox MB_OK|MB_ICONEXCLAMATION "$(OldInstNotRemoved)"
Delete "$TEMP\uninst123.exe"
ClearErrors
-------------------------------------------

It executes fine, it deletes all files fine, but it doesn't wait for the uninstaller to finish.
$INSTDIR is set to $TEMP and shows that in the messagebox just fine. Everything is copied or deleted where it should, it's just not waiting.
I've tried messing with the quotes as proposed in this thread but it doesn't work if I'm leaving out either of the quotes.
Well, both strings do contain spaces, but I also tried _?=C:\ with or without quotes (the one without quotes doesn't start at all) and no success...
I've also tried to set the $INSTDIR to the directory where the uninst.exe was placed during install - no luck.
I've tried to just starting the uninstaller without the _?XXX option - still no luck.
I've looked at the makensis.nsi script to see what they're doing different but other than not using quotes (which is on purpose according to kichik in another thread because the variables alread contain quotes) I can't see a difference...
I'm out of my wits ...
Thanks for any more help on this...


This example works fine:


!include MUI.nsh

OutFile 'testing.exe'

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_INSTFILES

!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_INSTFILES

!insertmacro MUI_LANGUAGE English

Section Uninstall
SectionEnd

Section

StrCpy $INSTDIR "$EXEDIR\temp"
SetOutPath $INSTDIR

WriteUninstaller "$EXEDIR\uninstall.exe"
CopyFiles "$EXEDIR\uninstall.exe" "$TEMP\uninstall.exe"
ExecWait '"$TEMP\uninstall.exe" _?=$INSTDIR'
Delete "$TEMP\uninstall.exe"

SectionEnd


-Stu

OK, I got it working now, thanks for all your help.
The solution, however, is kind of strange.
I defined the InstallDir like this (straigh after all the !include pages)


; MUI end ------

Name "${PRODUCT_NAME}"
InstallDir "$TEMP"
OutFile "Setup.exe"
ShowInstDetails show
ShowUnInstDetails show
SetCompress off
CRCCheck force


Now, in .onInit I wrote the check for prior versions and did the uninstall if neccessary. I checked with a MB_OK that the path for $INSTDIR was correctly set (which it was). That didn't help as I stated above.
Now thanks to the last script-example of Stu I got the missing point: StrCpy $INSTDIR "$TEMP" straight before doing the check and the uninstalling does the trick.

So this is what my solution looks like:

ClearErrors
StrCpy $INSTDIR "$TEMP"
ReadRegStr $R1 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString"
IfErrors +8 0
MessageBox MB_YESNO|MB_ICONQUESTION|MB_DefButton1 "$(OldInstFound)" IDYES 0 IDNO +7
ClearErrors
CopyFiles /SILENT "$R1" "$TEMP\uninst123.exe"
ExecWait '"$TEMP\uninst123.exe" _?=$INSTDIR'
IfErrors 0 +2
MessageBox MB_OK|MB_ICONEXCLAMATION "$(OldInstNotRemoved)"
Delete "$TEMP\uninst123.exe"
ClearErrors


If I messagebox $INSTDIR before the StrCpy and after, it's the exact same string (due to InstallDir "$TEMP" above) but without the StrCpy I cannot leave out the quotes on the _?XXX section.
Let me make that clear: quotes on the _?XXX section of ExecWait will result in ExecWait failing. (Insert a MB_OK in Stu's script after the ExecWait and play with the quotes - MB will pop in the backgroung with quotes but won't without)
Notice that in neither ways of defining $INSTDIR the variable itself contains quotes, but without doing a StrCpy the _?XXX part without quotes is failing to execute the uninstaller and with quotes it's failing to wait for the uninstaller.
Hope this can help someone in the future and thanks again for all your advice

Martin

Actually, the solution is not to use quotes around the _=? parameter. See chapter 3 of the documentation for more information.


So Afro in your example, you suggest having another script purely for the uninstaller, you can't bundle it in with the original install script? I don't see how that example won't just uninstall anything immediately after it's installed otherwise.


The compiled installer which should be used as the uninstaller would indeed uninstall everything, if you execute it. But the idea is not the execute it and instead extract it from the installer as the uninstaller.


Right, I guess I was hoping I could create both installer and uninstaller in the same script as I had been doing before, but it's not the end of the world if I have to use two files.