Question

In silent install mode the user is not asked about the installation target with the PageEx directory, and therefore the functions DirVerify and GetInstDirError are never called.

This is also applicable to installs that hardcode the installation target (a bad idea) for the same reason as above: the PageEx directory is never invoked.

Was it helpful?

Solution

Your sample code is ok, but calling ${DriveSpace} on Win9x could fail. I also removed the need to specify the section id's

!define APPNAME "CalcEnoughSpace"
name "${APPNAME}"
outfile "$%temp%\${APPNAME}.exe"
ShowInstDetails show
RequestExecutionLevel user
installdir "$Temp"
AllowRootDirInstall true

!include Sections.nsh
!include LogicLib.nsh

Function .onInit
push $instdir
call VerifyFreeSpace
pop $0
${If} $0 < 1
    MessageBox mb_iconstop "Not enough free space!"
${EndIf}
FunctionEnd

page instfiles

Section !a
AddSize 10000
SectionEnd
Section /o b
AddSize 10000
SectionEnd

SectionGroup grp
Section c
AddSize 10000
SectionEnd
SectionGroupEnd



Function VerifyFreeSpace
System::Store s
pop $0 ;path to check
Push 0 ;default to no
System::Call 'kernel32::GetDiskFreeSpaceEx(tr0,*l.r1,*l,*l)i.r2'
${If} $2 < 1 
    StrCpy $0 $0 3
    System::Call 'kernel32::GetDiskFreeSpace(tr0,*i.r1,*i.r2,*i.r3,*i)i.r4'
    IntCmpU $4 0 ret 
    IntOp $1 $1 * $2
    System::Int64Op $1 * $3
    pop $1  
${EndIf}
System::Int64Op $1 / 1024 ;to kb
pop $1
StrCpy $4 0 ;size
StrCpy $2 0 ;section idx
loop:
    ClearErrors
    SectionGetFlags $2 $3
    IfErrors testspace
    IntOp $3 $3 & ${SF_SELECTED}
    ${If} $3 <> 0
        SectionGetSize $2 $3
        IntOp $4 $4 + $3
        ${EndIf}
    IntOp $2 $2 + 1
    goto loop
testspace:
pop $2 ;throw away default return value
System::Int64Op $1 > $4
ret:
System::Store l
FunctionEnd

I only did limited testing, hopefully there are no bugs :)

OTHER TIPS

I wrote a function called CheckFreeSpace in NSIS to do this. Unfortunately it has the following limitations:

  • To compute the size of all the sections in your installation, you have to modify CheckFreeSpace to add each section, by knowing each variable that each section id was written into. I can't find a way of iterating over all sections that will be installed using NSIS.
  • Installation drive must be computed because ${DriveSpace} requires a drive letter, not a path to an arbitrary directory. The drive letter string is computed with StrCpy $instdrive $INSTDIR 3. If the $INSTDIR variable is a relative path or does not begin with a string such as C:\, this will fail.
  • If the installation cannot continue it produces a MessageBox. You can suppress the MessageBox by adding /SD IDOK at the end of the statement, but then the user is not informed of the installation failure: I can't find a way to emit to stdout from NSIS. Perhaps the return code from the installer is enough?
  • If the disk free space is really low (like 10kb), the installer won't run at all; it doesn't have space to unpack its temporary DLL's into the \tmp directory.

Also, in my implementation below, CheckFreeSpace has a hardcoded value for the space free after installation. Obviously that can be parameterized.

Here it is within a sample installer:

!include FileFunc.nsh
!insertmacro DriveSpace

Name "CheckFreeSpace"
OutFile "C:\CheckFreeSpace.exe"

InstallDir C:\tmp\checkfreespace

Page instfiles

Section "install_section" install_section_id
    Call CheckFreeSpace

    CreateDirectory $INSTDIR
    SetOutPath $INSTDIR
    File "C:\installme.bat"

    WriteUninstaller "$INSTDIR\Uninstall.exe"

    DetailPrint "Installation Successful."
SectionEnd

Section "Uninstall"

    RMDIR /r "$INSTDIR"

SectionEnd

Function CheckFreeSpace

    var /GLOBAL installsize
    var /GLOBAL adjustedinstallsize
    var /GLOBAL freespace
    var /GLOBAL instdrive

    ; Verify that we have sufficient space for the install

    ; SectionGetSize returns the size of each section in kilobyte.
    SectionGetSize ${install_section_id} $installsize

    ; Adjust the required install size by 10mb, as a minimum amount
    ; of free space left after installation.
    IntOp $adjustedinstallsize $installsize + 10240

    ; Compute the drive that is the installation target; the
    ; ${DriveSpace} macro will not accept a path, it must be a drive.
    StrCpy $instdrive $INSTDIR 3

    ; Compute drive space free in kilobyte
    ${DriveSpace} $instdrive "/D=F /S=K" $freespace

    DetailPrint "Determined installer needs $adjustedinstallsize kb ($installsize kb) while $freespace kb is free"

    IntCmp $adjustedinstallsize $freespace spaceok spaceok

    MessageBox MB_OK|MB_ICONSTOP "Insufficient space for installation. Please free space for installation directory $INSTDIR and try again."
    DetailPrint "Insufficient space for installation. Installer needs $adjustedinstallsize kb, but freespace is only $freespace kb."
    Abort "Insufficient space for installation."

  spaceok:
    DetailPrint "Installation target space is sufficient"

FunctionEnd

Do you have a sample script for silent install?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top