Conditional SetOverwrite - nsis

I am trying to dynamically set the SetOverwrite state for choosing between unconditionally replace some files or replace them only if my setup is providing some newer versions.
I have tried with logiclib
${if} $isReinstall = 1
SetOverwrite on
${debug} "SetOverwrite on (overwrite)"
${else}
SetOverwrite ifnewer
${debug} "SetOverwrite ifnewer"
${endif}
File "foo"
And with classic IntCmp
IntCmp $isReinstall 1 0 +3 +3
SetOverwrite on
goto +2
SetOverwrite ifnewer
File "foo"
But nothing seem to work: if my file foo is already present on disk, it is always skipped. My $isReinstall being 1 or not.
It seems that the last SetOverwrite statement in the stream of instructions (regardless of the logiclib macros) overloads the previous one.
If I add another SetOverwrite on just before the File directive, the file is correctly replaced.
Is my analysis correct? How could I decide at runtime if a file can or cannot be replaced?

Try using this code instead:
${If} $isReinstall = 1
SetOverwrite on
File "foo"
${Else}
SetOverwrite ifnewer
File "foo"
${EndIf}
The important point to note is that the File command appears within the If block and this needs to be done because the SetOverwrite command affects every line below it. See this piece of the NSIS documentation for a full explanation.

Related

DLL Function is not calling from the NSIS installer when uninstalling

When uninstaling the software to do the complete cleanup calling the function in the C++ DLL .
To achieve this I am placing the DLL file in the temp directory. Then in the Uninstall section calling the DLL function. But it is not calling the function.
If I place that DLL file in the installed directory then it is calling the DLL function.
But I should not place it in the installed directory because I am calling this function when uninstalling.
Is it the correct way that I am doing? or is there any other way?
Below is my code snippet:
Section "MyApp"
InitPluginsDir
SetOutPath $PluginsDir
File "C:\Desktop\KillNofificationSoftly.dll"
SetOutPath $Temp
MessageBox MB_OK "Temp Path $Temp"
System::Call 'KERNEL32::AddDllDirectory(w "$PluginsDir")'
SetOutPath $INSTDIR
SectionEnd
Section "Uninstall"
System::Call "$PluginsDir\KillNofificationSoftly.dll::KillMeSoftly() i.r0 ?e"
Pop $1 ; LastError
${If} $0 = 0
MessageBox MB_OK "Success"
${EndIf}
SectionEnd
You are extracting the .DLL in the installer! $PluginsDir is deleted when the installer finishes. Move all the code to the uninstaller section.
If you are the author of this .DLL you should consider writing a NSIS plug-in, then it becomes just a single line of code, no need for System::Call.

IfFileExists command run 3 command lines

How do I the result of IfFileExists command run three lines and not only the first.
In the code below is the result of IfFileExists is TemWSConfig, must perform the 3 lines to the NaoTemWSConfig command.
Presently the line 2 and 3 after TemWSConfig, always run
IfFileExists "$INSTDIR\IntegradorWS.exe.Config" TemWSConfig NaoTemWSConfig
TemWSConfig:
File "..\IntegradorWS\bin\x86\Release\AppInstalado.config"
Rename "$INSTDIR\IntegradorWS.exe.Config" "$INSTDIR\Antigo_IntegradorWS.exe.Config"
Rename "$INSTDIR\AppInstalado.config" "$INSTDIR\IntegradorWS.exe.Config"
NaoTemWSConfig:
File "..\IntegradorWS\bin\x86\Release\IntegradorWS.exe.Config"
NSIS does not skip around like this, you can verify that by switching out the problematic instructions:
Section
; Fake the IntegradorWS.exe.Config file for this example:
StrCpy $INSTDIR $temp
File "/oname=$INSTDIR\IntegradorWS.exe.Config" "${__FILE__}"
IfFileExists "$INSTDIR\IntegradorWS.exe.Config" TemWSConfig NaoTemWSConfig
TemWSConfig:
DetailPrint "TemWSConfig:1"
DetailPrint "TemWSConfig:2"
DetailPrint "TemWSConfig:3"
NaoTemWSConfig:
DetailPrint "NaoTemWSConfig:1"
; Clean up
Delete "$temp\IntegradorWS.exe.Config"
SectionEnd
This means the problem must be with the File instruction. Make sure you have called SetOutPath so it knows where to extract. File extraction can be skipped if you have changed SetOverwrite etc.

Nsis temp folder

Function .onInit
DetailPrint "Temp folder - $TEMP"
System::Call 'Kernel32::GetTempFileName(t $TEMP, t "tmp", i 0, t.r0) i.r1
DetailPrint "Temp folder name - $0" //$0 gives empty string
FunctionEnd
When I call Kernel32::GetTempFileName in .onInit function i retrieves an empty file name. But when i call it from section everything is ok!
Can you explain me why?
I recommend you just call InitPluginsDir in .onInit and use $PLUGINSDIR as temp folder. It will be deleted automatically on exit.
$PLUGINSDIR
The path to a temporary folder created upon the first usage of a
plug-in or a call to InitPluginsDir. This folder is automatically
deleted when the installer exits.
It is important to quote all string parameters when using System::Call:
Section
System::Call 'Kernel32::GetTempFileName(t "$TEMP", t "tmp", i 0, t.r0) i.r1'
DetailPrint |$0|
SectionEnd
Please consider using $pluginsdir like the other answer suggests, it is a much better solution because it will not leave behind junk on the end-users machine...

Is it possible to conditionally add a file/folder to NSIS installer

Is it possible to conditionally add a file/folder and installation option to a NSIS installer?
My idea is that if the folder Foo exists at a given location it should be added to the installer and the option to install Foo should be added to the installer as well. But if the folder Foo does not exist, the NSIS script should just create the installer but leave Foo and the option to select Foo out of it.
You can try to include a file with /NONFATAL. If it exists, it will be included by the compiler. In runtime, you can check if installer was able to extract it.
File /NONFATAL "file.zip"
${If} ${FileExists} "$OUTDIR\file.zip"
...
${EndIf}
In NSIS 2 File /NONFATAL /R "c:\foo" is the best you can do without external tools and you need a little hack to hide the section when there are no files:
!include LogicLib.nsh
Page Components
Page InstFiles
Section "Main"
SetOutPath $InstDir
# File "C:\myfiles\myapp.exe"
SectionEnd
Section "Install Foo" SID_FOO
SetOutPath $InstDir
File /NONFATAL /r "C:\myfiles\foo\*.*"
SectionEnd
Function .onInit
SectionGetSize ${SID_FOO} $0
StrCmp $0 0 "" +3
SectionSetFlags ${SID_FOO} 0 ; Force all flags off including the checkmark
SectionSetText ${SID_FOO} "" ; Hide the section because its size is 0
FunctionEnd
If this is unacceptable you can use !system and get a little help from cmd.exe to check if something exists:
!tempfile INCEXIST
!system 'if exist "C:\myfiles\foo\*.*" echo !define HAVE_FOO > "${INCEXIST}"'
!include "${INCEXIST}"
!delfile "${INCEXIST}"
!ifdef HAVE_FOO
Section "Install Foo"
SetOutPath $InstDir
File /r "C:\myfiles\foo\*.*"
SectionEnd
!endif
In NSIS 3 !if supports a /FileExists switch:
!if /FileExists "C:\myfiles\foo\*.*"
Section "Install Foo"
SetOutPath $InstDir
File /r "C:\myfiles\foo\*.*"
SectionEnd
!endif
Example to replace file what depends on running service and exists or not at targget location
IfFileExists "$SYSDIR\my_file.dll" exist notexist
exist:
ExecWait 'net stop desired_service'
SetOutPath $SYSDIR
SetOverwrite on
File "/oname=$SYSDIR\my_file.dll" "Path to my file\my_file.dll"
ExecWait 'net start desired_service'
notexist:
.....what you want to do if doesn't exists

Install from dynamic location

I have 2 versions of the same exe file for my project. The installer is supposed to pick one of the 2 versions depending on some conditions.
In a normal case i would do File executable\myExe.exe. Because i now have 2 versions of the file, i would have to do something like File "${ExeSourcePath}\myExe.exe", and $ExeSourcePath is determined by checking various conditions. When compiling this code i get
File: "${ExeSourcePath}\myExe.exe" -> no files found.
Anyone knows why? I'm only allowed to use fixed paths with the File command or am i doing something wrong?
${ExeSourcePath} is a precompiler define and $ExeSourcePath is a variable used at runtime, the File command can only use precompiler defines.
There are two ways you can handle this:
A) Include both files and decide at runtime based on the users system or choices made during install:
!include LogicLib.nsh
Section
ReadRegStr $0 HKLM "Software\foo\bar" baz
${If} $0 > 5
File "c:\myproject\version2\app.exe"
${Else}
File "c:\myproject\version1\app.exe"
${EndIf}
SectionEnd
B) Only include one file based on command line passed to makensis (/Dusev2 app.nsi) or something on your system:
Section
!define projectroot "c:\myproject"
!searchparse /noerrors /file ....... usev2 ;Or you can use !system etc
!ifdef usev2
File "${projectroot}\version2\app.exe"
!else
File "${projectroot}\version1\app.exe"
!endif
SectionEnd

Resources