Come posso controllare lo spazio libero nel corso di una installazione non presidiata NullSoft?
Domanda
In modalità di installazione silenziosa l'utente non viene chiesto il bersaglio di installazione con il PageEx directory
, e quindi le funzioni DirVerify
e noreferrer GetInstDirError
non vengono mai chiamati.
Questo è applicabile anche alle installazioni che hardcode l'obiettivo di installazione (una cattiva idea) per lo stesso motivo di cui sopra:. La PageEx directory
non è mai invocato
Soluzione
Il codice di esempio è ok, ma $ chiamando {} DriveSpace su Win9x potrebbe fallire. Ho anche rimosso la necessità di specificare la sezione id
!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
Ho fatto solo limitato di test, speriamo che non ci sono bug:)
Altri suggerimenti
ho scritto una funzione chiamata CheckFreeSpace
in NSIS per fare questo. Purtroppo ha le seguenti limitazioni:
- Per calcolare le dimensioni di tutte le sezioni in vostra installazione, è necessario modificare
CheckFreeSpace
per aggiungere ogni sezione, conoscendo ogni variabile che ogni id sezione è stata scritta in. Non riesco a trovare un modo di iterare su tutte le sezioni che verranno installati utilizzando NSIS. - unità di installazione deve essere calcolato perché
${DriveSpace}
richiede una lettera di unità, non un percorso a una directory arbitraria. La stringa lettera dell'unità viene calcolata conStrCpy $instdrive $INSTDIR 3
. Se la variabile$INSTDIR
è un percorso relativo o non inizia con una stringa comeC:\
, questo sarà sicuro. - Se l'installazione non può continuare produce un
MessageBox
. È possibile sopprimere laMessageBox
aggiungendo/SD IDOK
alla fine della dichiarazione, ma poi l'utente non viene informato del fallimento di installazione: non riesco a trovare un modo per emettere astdout
da NSIS. Forse il codice di ritorno dal programma di installazione è sufficiente? - Se lo spazio libero su disco è davvero basso (come 10kb), il programma di installazione non funzionerà affatto; non ha spazio per disfare la sua temporanea DLL nella directory
\tmp
.
Inoltre, nella mia implementazione di seguito, CheckFreeSpace
ha un valore hardcoded per lo spazio libero dopo l'installazione. Ovviamente che possono essere parametrizzate.
Qui è all'interno di un programma di installazione di esempio:
!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
Hai uno script di esempio per l'installazione silenziosa?