Archive: Syntax question


Syntax question
I have this in my uninstall section:

Section "Uninstall"
!include "$instdir\unifilelist.nsh"
SectionEnd

I keep getting this error though:
!include: could not find: "$instdir\unifilelist.nsh"

The file is in the $instdir, if I remove $instdir and put in a hardcoded value everything works.

For example this works:
Section "Uninstall"
!include "c:\somefolder\unifilelist.nsh"
SectionEnd

How do I include variables in that !include directive?


"!include" is a preprocessor command, evaluated at compile time. But $INSTDIR is a variable, which will have a value only at runtime, when the installer is executed. You shouldn't mix that up! Define a symbol instead! Try like this:

!define uninstfile "c:\somefolder\unifilelist.nsh"

...

Section "Uninstall"
!include "${uninstfile}"
SectionEnd

But the file will be inside the install directory, and since the install directory will be different with each install is there a way to make this whole process dynamic?

I cant do this either because it still gives me the same error:
!define unfiles "$instdir\unifilelist.nsh"


You can't include a .nsh file from the user's install directory! That's because the "!include" instruction is a preprocessor command that will be evaluated at the moment when you *compile* the installer! It will *not* be evaluated when the user runs the installer/uninstaller, like normal installer instructions. Therefore the "!include" command requires a path to some file on your local machine, which needs to be present at the moment when you *compile* your installer. Hope that is clear now!

BTW: The same applies to all preprocessor commands. Those can be easily identified, because they start with a "!" character ;)


Ok that makes sense. What is norm in this situation then? If people use a list of files to build the uninstall section, do they just hard code where that file will reside?


Originally posted by patelb
Ok that makes sense. What is norm in this situation then? If people use a list of files to build the uninstall section, do they just hard code where that file will reside?
Either that, or you load the file names from a plain text file at *runtime* like this:

Section "Uninstall"
ClearErrors
FileOpen $0 "$INSTDIR\files.lst" r
IfErrors done

Loop:
FileRead $0 $1
IfErrors LoopEnd
Delete "$1"
Goto Loop
LoopEnd:

FileClose $0
done:
SectionEnd


The "files.lst" would need to look like:

C:\Program Files\Foobar Deluxe\File1.foo
C:\Program Files\Foobar Deluxe\File2.foo
C:\Program Files\Foobar Deluxe\File3.foo
...


The "files.lst" must be generated during install...

Very clever!


Nevertheless, in most cases you will be fine with:

Section "Uninstall"
RMDir /r /REBOOTOK "$INSTDIR"
SectionEnd


The variable $INSTDIR will contain the install directory selected by the user at *runtime* and it is available in both, the installer and uninstaller. The uninstaller code above will simply remove the entire Install folder including all files and subdirectories. Also all files added *after* install would be erased...

For an advanced solution have a look at:
http://nsis.sourceforge.net/Advanced...og_NSIS_Header

I thought this was unsafe:

_http://forums.winamp.com/showthread.php?s=&threadid=289986


Well, I'd say it's safe. In the uninstaller $INSTDIR will contain the path where the "Uninstall.exe" is located. That should be the Install folder of your application, otherwise your Uninstall.exe is mislocated! So as long as you don't expect the user to store any important files within your Install folder, it should be save to erase the $INSTDIR folder at uninstall. More subtle solutions can be implement using $INSTDIR, like "Delete $INSTDIR\Bin\*.exe", instead of deleting the entire $INSTDIR folder. And if you want an advanced solution, see the link from my previous post...

BTW: Are Hyperlinks in my posts visible to other users? :confused:


I can see them


Good :)

Also keep in mind that when you store *full* paths during install, the Uninstaller would fail horrible if the user renamed or moved the installer folder! Therefore I would use $INSTDIR in my uninstaller to avoid such problem. Even if you want to store all files in a text file and read that text file during uninstall, I would *not* use full paths (as shown in my example above). I would store paths *relative* to the $INSTDIR folder, so when the user moves or renames the Install folder, your uninstaller still works...

Section "Uninstall"
ClearErrors
FileOpen $0 "$INSTDIR\files.lst" r
IfErrors done

Loop:
FileRead $0 $1
IfErrors LoopEnd
Delete "$INSTDIR\$1" ; <- SEE HERE
Goto Loop
LoopEnd:

FileClose $0
done:
SectionEnd


File1.foo
File2.foo
Data\File3.foo
Data\File4.foo
Data\Stuff\File5.foo
...

That "looping" solution you gave me earlier, on the fileread command its reading the line break also. So the delete command is not working properly. Is there like a chomp function in nsis that will fix this?


See "NSIS\Docs\StrFunc\StrFunc.txt" for info ;)

Look out for ${StrTrimNewLines} :D



Fixed code should look like:

!include "StrFunc.nsh"
${StrTrimNewLines}

Section "Uninstall"
ClearErrors
FileOpen $0 "$INSTDIR\files.lst" r
IfErrors done

Loop:
FileRead $0 $1
IfErrors LoopEnd
${StrTrimNewLines} $2 "$1" ; <- Remove carriage returns
Delete "$INSTDIR\$2"
Goto Loop
LoopEnd:

FileClose $0
done:
SectionEnd


files.lst:
File1.foo
File2.foo
Data\File3.foo
Data\File4.foo
Data\Stuff\File5.foo
...