NSIS, detect if directory exists during installation - installation

I have installer, which supports choosing installation directory. And I want to detect if given folder exists and if it is empty. If it is NOT empty, show warning message box, then remove all its contents and install program into that folder. Only problem is to get into the right code section, where I can get installation folder given by user during installation, I can handle the rest.
Thank you for any advices.

Normally you would just check if the directory exists:
Outfile "$%Temp%\Test.exe"
RequestExecutionLevel user
InstallDir "$Documents\Test"
!include LogicLib.nsh
Page Directory "" "" DirLeave
Page InstFiles
Function DirLeave
${If} ${FileExists} "$InstDir\*"
MessageBox MB_YESNO `"$InstDir" already exists, delete it's content and continue installing?` IDYES yep
Abort
yep:
RMDir /r "$InstDir"
${EndIf}
FunctionEnd
Section
SetOutPath $InstDir
File myfile.ext
SectionEnd
This will also display the message if the directory exists but is empty. To work around that you would need some custom detection:
!macro _IsNonEmptyDirectory _a _b _t _f
!insertmacro _LOGICLIB_TEMP
!insertmacro _IncreaseCounter
Push $0
FindFirst $0 $_LOGICLIB_TEMP "${_b}\*"
_IsNonEmptyDirectory_loop${LOGICLIB_COUNTER}:
StrCmp "" $_LOGICLIB_TEMP _IsNonEmptyDirectory_done${LOGICLIB_COUNTER}
StrCmp "." $_LOGICLIB_TEMP +2
StrCmp ".." $_LOGICLIB_TEMP 0 _IsNonEmptyDirectory_done${LOGICLIB_COUNTER}
FindNext $0 $_LOGICLIB_TEMP
Goto _IsNonEmptyDirectory_loop${LOGICLIB_COUNTER}
_IsNonEmptyDirectory_done${LOGICLIB_COUNTER}:
FindClose $0
Pop $0
!insertmacro _!= "" $_LOGICLIB_TEMP `${_t}` `${_f}`
!macroend
!define IsNonEmptyDirectory `"" IsNonEmptyDirectory`
Function DirLeave
${If} ${IsNonEmptyDirectory} "$InstDir"
MessageBox MB_YESNO `"$InstDir" already exists, delete it's content and continue installing?` IDYES yep
Abort
yep:
RMDir /r "$InstDir"
${EndIf}
FunctionEnd

Related

Unable to write Registry files using NSIS

I have the following code snippet used to write the registry files to the path :
;Registry and SDK Setup
Section "mySection"
SetOverwrite on
SetOutPath "C:\ProgramData\....\Gadgets"
File "{....KEYS...}.png"
File "{....KEYS...}.xml"
WriteRegStr HKLM "...\STC\Gadgets\{....KEYS...}" "toastAction""DisableToast"
SectionEnd
The above code fails to write the registry files. Could someone help me find the issue?
You need to set the $INSTDIR variable to indicate the destination directory. MUI 2 has a ready made page to let the user choose the destination folder. It's called MUI_PAGE_DIRECTORY:
!include "MUI2.nsh"
Name "Test"
Outfile "test.exe"
InstallDir "$LOCALAPPDATA\test"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section
SetOutPath "$INSTDIR"
;Use File to copy files to destination folder.
SectionEnd

NSD_GetState returns 0 always: NSIS

I was trying to include a check box in my uninstaller. I was able to put the check box in place. But when I try to get the state of check box it always returns 0 even though check box is checked. Here is the code I am using
!define MUI_WELCOMEPAGE_TITLE_3LINES
!define MUI_PAGE_CUSTOMFUNCTION_SHOW un.ModifyUnWelcome
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_INSTFILES
!define MUI_FINISHPAGE_TITLE_3LINES
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.LeaveUnWelcome
!insertmacro MUI_UNPAGE_FINISH
Function un.ModifyUnWelcome
${NSD_CreateCheckbox} 120u -18u 50% 25u "Do something special"
Pop $mycheckbox
SetCtlColors $mycheckbox "" ${MUI_BGCOLOR}
${NSD_Check} $mycheckbox ; Check it by default
FunctionEnd
Function un.LeaveUnWelcome
${NSD_GetState} $mycheckbox $0
MessageBox MB_OK "On Leave mycheckbox = $mycheckbox $\n $$0 = $0"
${If} $0 <> 0
MessageBox mb_ok "I'm special"
${EndIf}
FunctionEnd
As a result I could not verify if the check box is checked or not.
what is wrong with my code and how can I fix it?
I even tried something like below
${NSD_Check} $mycheckbox ; Check it by default
${NSD_SetState} $mycheckbox ${BST_CHECKED}
I got the above code from Adding a checkbox to the NSIS Uninstaller Welcome Page
Your custom functions referred to two different pages.
ModifyUnWelcome is calling when creates MUI_UNPAGE_WELCOME page, LeaveUnWelcome - when user leaves last MUI_UNPAGE_FINISH page.
Control, owned by handle at ModifyUnWelcome will be destroyed at the moment when you are calling ${NSD_GetState}. You should to place custom functions definitions near each other and before referred page declaration.
!define MUI_WELCOMEPAGE_TITLE_3LINES
!define MUI_PAGE_CUSTOMFUNCTION_SHOW un.ModifyUnWelcome
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.LeaveUnWelcome
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_INSTFILES
!define MUI_FINISHPAGE_TITLE_3LINES
!insertmacro MUI_UNPAGE_FINISH

NSIS - Install a file to a pre-existing, uncertain subfolder?

I'm trying to install a file to a pre-existing folder structured like this:
$APPDATA/somefolder/(uncertainFolder)
The "uncertainFolder" would be either "1.0" or "2.0".
The same file will be installed into the "uncertainFolder" despite the folder name difference. How can I achieve this?
Thank you in advance.
Files installed with the File instruction are extracted into the directory set by SetOutPath. Changing this path at run-time is not a problem once you know which folder you want.
If the possible folder names are known at compile-time you can use if/or if/else:
!include LogicLib.nsh
${If} ${FileExists} "$InstDir\SomeFolder\2.0\*.*"
SetOutPath "$InstDir\SomeFolder\2.0"
${Else}
SetOutPath "$InstDir\SomeFolder\1.0"
${EndIf}
You can also enumerate files and folders at run-time:
FindFirst $0 $1 "$InstDir\SomeFolder\*.*"
loop:
StrCmp $1 "" end ; No more files?
StrCmp $1 "." next ; DOS special name
StrCmp $1 ".." next ; DOS special name
IfFileExists "$InstDir\SomeFolder\$1\*.*" 0 next ; Skip files
DetailPrint "$1 is a folder in $InstDir\SomeFolder"
SetOutPath "$InstDir\SomeFolder\$1"
Goto end ; This stops the search at the first folder it finds
next:
FindNext $0 $1
goto loop
end:
FindClose $0
The Locate macro in FileFunc.nsh is built on top of FindFirst/FindNext and can also be used if you prefer its syntax...

overwrite files created by emmbeded installer

So I embedded two installers into my install script created with nsis, the whole thing is supposed to install one program then the other one, and then overwrite three files created by the second installer with newer versions. The problem is that those three files get created before the second installer gets to work. How can I make sure that these files get created only after the second installer finish it's job?
`
!include "MUI2.nsh"
; The name of the installer
Name "ADIS"
RequestExecutionLevel user
; The file to write
OutFile "ADIS.exe"
Unicode true
; The default installation directory
InstallDir "C:\ADIS"
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE "Spanish"
;--------------------------------
; The stuff to install
Section ""
; Set output path to the installation directory.
SetOutPath $INSTDIR
RMDir /r $INSTDIR
SectionEnd
SectionGroup "instaladores"
Section "Firebird"
ExecWait "Firebird\Firebird-2.5.4.26856_0_Win32.exe"
SectionEnd
Section "Cliente"a
ExecWait "Cliente\setup.exe"
SectionEnd
SectionGroupEnd
Section "Actualiza"
; Put file there
;File Nvo\ADIS.exe
;File Nvo\ADIS.ICO
;File Nvo\ADIS.GDB
File /r "Nvo\*"
SectionEnd`
You should probably run "Cliente\setup.exe" silently. Most installers have a silent switch you can use on the command line and some also provide a wait switch so you can wait even if the installer uses child processes.
What happens if you add a MessageBox before the file command and don't click it until the other installers have completed?

NSIS weird behavior with GetParameters

I'm having a weird error with NSIS:
!include "MUI2.nsh"
!include "FileFunc.nsh" # To use GetParameters
Name nsDialogs
OutFile nsDialogs.exe
Function .onInit
${GetParameters} $R0
MessageBox MB_OK "$R0"
FunctionEnd
!insertmacro MUI_PAGE_WELCOME
Section
DetailPrint "hello world"
SectionEnd
If I use this command line
nsDialogs.exe /d=hello
the message box says: "/d=hello" as expected, but if I use
nsDialogs.exe /D=hello
the message box says "" and this is wrong.
Why is this happening?
From the documentation:
/D sets the default installation directory ($INSTDIR), overriding
InstallDir and InstallDirRegKey. It must be the last parameter used in
the command line and must not contain any quotes, even if the path
contains spaces. Only absolute paths are supported.
This means you cannot use /D with ${GetParameters} (/S and /NCRC are also switches used by NSIS). NSIS by design uses everything after /D= as $instdir.
The only way to detect /D is to not use InstallDir[RegKey] in your script and check if $instdir is != "" in .onInit
/D is command line parameter that let define the installation directory directly from the installer command line invocation.
See the Installer usage / Common Options chapter for details.
I don't know for sure, but I assume that NSIS strips out its inbuilt parameters by default. In that case you could try something like this:
!define myInstDir "$PROGRAMFILES\myApp"
Function .onInit
${GetParameters} $R0
StrCpy $R0 ${myInstDir} +2
MessageBox MB_OK "$$INSTDIR was changed on runtime"
FunctionEnd

Resources