Archive: Updating Space required after setting $INSTDIR


Updating Space required after setting $INSTDIR
In my installer I am copying a 100MB file from a CD to the installation directory using FileCopy. The installer first does MUI_PAGE_COMPONENTS, then asks where to find the file from the CD (called arc.sar), and after that gets to the MUI_PAGE_DIRECTORY. What I want the installer to do is first get $INSTDIR on the DIRECTORY page, then check if $INSTDIR\arc.sar exists, and then substract arc.sar's size from the required free space, updating the Space Required: label on that same page, the DIRECTORY page.

Some parts of the script:


!insertmacro MUI_PAGE_COMPONENTS
;Custom page: asks where to find arc.sar
Page custom GetSarLocation CheckSarLocation
;Find arc.sar in $INSTDIR and substract filesize
!define MUI_PAGE_CUSTOMFUNCTION_PRE CheckExistingSar
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES

Function CheckExistingSar
IfFileExists "$INSTDIR\arc.sar" 0 NoExistingSar
Push "$INSTDIR\arc.sar"
Call FileSizeNew
Pop $EXISTING_SAR_SIZE
IntOp $EXISTING_SAR_SIZE $EXISTING_SAR_SIZE % -1000
SectionGetSize CommonInstall $2
IntOp $2 $2 - EXISTING_SAR_SIZE
SectionSetSize CommonInstall $2

NoExistingSar:
FunctionEnd


As you can see I've tried to use PAGE_CUSTOMFUNCTION_PRE on PAGE_DIRECTORY, and indeed the function CheckExistingSar updates the size of the CommonInstall section succesfully if it can find arc.sar. Only the 'Space required' value does not change, and the CheckExistingSar function is in fact called only once. Entering a different install path does not call the function again.

I've read some hints about using FindWindow etc commands to manually influence the label, but I have no clue how to go about this. Any help would be greatly appreciated.

You should call the CheckExistingSar function in .onVerifyInstDir. That'd update the required size every time the installation directory changes.


Obviously I'm not yet used to the way NSIS works... Thanks for the tip.

Because .onVerifyInstDir is called multiple times, I had to create an empty, hidden section that I set to a certain size (instead of decreasing the size of CommonInstall, because that would keep decreasing each time the function is called).

Section "-Install Nothing" EmptyInstall
NOP
SectionEnd

Function .onVerifyInstDir
IfFileExists "$INSTDIR\arc.sar" 0 NoExistingSar

<get filesize of arc.sar in $INSTDIR>
<divide $EXISTING_SAR_SIZE by 1024 and round it>

IntOp $2 -1 * $EXISTING_SAR_SIZE
SectionSetSize EmptyInstall $2

NoExistingSar:
FunctionEnd


The first problem is that when I enter .onVerifyInstDir for the first time, before doing anything, NSIS tells me that EmptyInstall is 4812 kB large, which seems kind of large for a NOP...
The second problem is that, even while I succesfully SectionSetSize EmptyInstall to be -100880 kB large, the Space required field remains unchanged. If I set EmptyInstall to +100880kB, it still doesn't update anything. Am I forgetting something?

You're setting the size of your first section and not the new section. You need to use ${EmptyInstall} with section commands. It's a define, so you must use curly brackets with it. If you don't, SectionSetSize will try to get a number out of the string "EmptyInstall" and will always get to zero, which is the index of the first section.


You are, of course, correct. This is the biggest problem I have with learning NSIS, I cannot find any documentation about the basic syntax. Just these things like what {} mean, how I put variables in a string, the very basic stuff. I'm using trial and error, which is probably the worst possible way to figure it out...

This works... Kind of. .onVerifyInstDir is however not called often enough. For example when I start install and reach the DIRECTORY page normally, it does not verify the default directory that is already filled in. Going Back and then Next again doesn't update it either. Typing a different directory then pressing Tab, still nothing.
I have to click 'browse' or 'next' before it will enter .onVerifyInstDir, and I cannot click 'next' because the installer thinks I don't have enough space (while I do, because I'll be overwriting arc.sar).

I could add an extra CheckExistingSar call in the PAGE_PRE function, but that still doesn't solve the problem of manually typing in an installation directory. I'd need it to update every time I type a character, not just when I change the Drive letter at the front.


Well, it's all there in the documentation. The description for `Section` points to the fact that the section index is !define. However, there's no example, it doesn't link to !define and doesn't explain the consequences. I've updated the documentation to fix those problems and added a few code examples in the description for Section(Get|Set)X.

.onVerifyInstDir is only called when the installation directory is changed and is still valid. If $INSTDIR is invalid to start with, .onVerifyInstDir will not be called. It also means that the size is checked and updated on screen before it's called. Because of that, the directory will have to be updated twice before the user will see your change. One time for the new size and the next for the update itself.

To get around it, you can force the window to update itself after the size changes. Not the simplest thing on earth, because .onVerifyInstDir isn't exactly built for that, as the name suggests. But it works.

!define WM_IN_UPDATEMSG 0x40f

Function .onVerifyInstDir
# lock to prevent infinite recursion
StrCmp $1 lock 0 +2
Return
StrCpy $1 lock

# do whatever
SectionGetSize 0 $0
IntOp $0 $0 + 100
SectionSetSize 0 $0

# update
FindWindow $0 "#32770" "" $HWNDPARENT
SendMessage $0 ${WM_IN_UPDATEMSG} 0 0

# unlock
StrCpy $1 ""
FunctionEnd

I can't say I really understand what that code does... But putting CheckExistingSar instead of #dowhatever still works only halfway. NSIS still doesn't reach .onVerifyInstDir if the default dir has too little free space to continue. If however the default dir is on a drive with free space, the updating after each keystroke does appear to work.

Unless you'd like to try another idea, I think I will drop the issue - it's not a very important feature. In any case, thanks a lot for the help so far.


Right, the solution was only for the second part of the problem. For updating the text. .onVerifyInstDir is still called only once the directory is valid in all other areas.

You can have the required size set to zero by default, have .onVerifyInstDir call Abort to tell the directory is invalid and only set the required size once the directory is valid and contains that RAR file. It will still be a problem if there isn't enough space and the user then immediately selects another directory because .onVerifyInstDir won't be called to update it.

That's the best I can think of at the moment. A second solution which isn't exactly the ideal, would be to use two pages or to test the free space for yourself, using CheckSpaceFree or something similar.