Archive: Add or Remove Programs - Size missing


Add or Remove Programs - Size missing
  Hi all,

I seem to have lost the Size attribute in the Add or Remove Programs list (XP).

The projected install size still appears in the setup (in the directory page).

I've tried removing the SectionSetSize calls to see if that might be causing it, but the size still won't show up in Add or Remove Programs. I know it should, but I don't know if it's something I did or a bug. Probably the former.

Where else can you save/store the size in a *.nsi script?

Using or not using AddSize also isn't responsible.

Many programs don't have a size in Add or Remove, and I don't consider it very important. Just puzzling...


AddSize or SectionSetSize have nothing to do with the Add/Remove Control Panel. Raymond Chen had a blog entry about the size attribute in there. It should shed some light on what's happening there. To sum it up, you should write the number of KBs into EstimatedSize in your uninstall key in the registry.


There must be more to it than meets the eye. Size is conspicuous only by its absence in Add/Remove Programs.

EstimatedSize was worth a try though. Thx.


The way it appears to me, is that windows checks the parent directory of the uninstaller and uses this directory size for display.

I currently have my uninstaller.exe in c:\temp
with the registry setting uninstallstring pointing to c:\temp\uninstall.exe. If i add for example a 100MB program into c:\temp - windows add/remove programs size increases by 100MB.

If i place the uninstaller into c:\ - and update the string to point to the new path c:\uninstall.exe - i no longer get a size, due to having no parent folder.

The size shown in add/remove programs seems to be the "size on disk" amount from folder properties.


Windows uses an algorithm to compute the size (imprecisely a lot of the time). Sometimes the parameters sought by the algorithm which derive from the name of your program and the files that are installed, are not present, so it would seem. According to the blog mentioned by Kichik (see above), you are able in such an event to override the algorithm by including your own dword in the reg that gives the exact size in KB: EstimatedSize.

To the annoyance of many, the dword value only applies if you install your software using an MSI installer. A search I did yesterday indicates that people have been trying without success to use EstimatedSize for some time; it only works with MSI.

In short, you can get the size by making sure the size algorithm finds the file/folder names it needs, or give up.


It works fine for me?
NSIS 2.45, Windows 7

Here are the relevant bits from my foo.nsi


[...]

!define ARP "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"

!include "FileFunc.nsh" ; for ${GetSize} for EstimatedSize registry entry

[...]

Section "Install"

; [...copy all files here, before GetSize...]

; get cumulative size of all files in and under install dir
; report the total in KB (decimal)
; place the answer into $0 (ignore $1 $2)
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2

; Convert the decimal KB value in $0 to DWORD
; put it right back into $0
IntFmt $0 "0x%08X" $0

; Create/Write the reg key with the dword value
WriteRegDWORD HKLM "${ARP}" "EstimatedSize" "$0"

[...write the other reg keys in ${ARP}...]

SectionEnd

[...]

${GetSize} gets the real size, as opposed to the size on disk. As I understand it, the Add/Remove programs number, if done correctly, is the size on disk, the size needed by the software before running out of disk space in the worst case situation. The size on disk value varies according to the file system, FAT32 or NTFS, and the drive's cluster size apparently.

The NSIS documentation does not clearly state which of the two sizes the installer automatically calculates to determine the Space Required.

Maybe someone, who has that knowledge, could provide an answer. My guess is it's the real size.


I had an idea -- a cut-and-paste job, like most of my ideas are. To obtain the size on disk, you can modify "GetSize" in FileFunc.nsh.

For documentation, see the NSIS user manual: E.1.3 GetSize.
Three variables are returned,

$var1 ; Result1: Size on disk
$var2 ; Result2: Sum of files
$var3 ; Result3: Sum of directories

...


Push $8
Push$9
; insert code
Push $R1
Push $R2
; end insert
Push $R3
Push $R4

>...

FileFunc_GetSize_file:
StrCpy $R6 0
StrCmp$5$6 '' 0 +3
IntOp $R4 $R4+ 1
goto FileFunc_GetSize_findnext
FileOpen$9 '$R8\$R7' r
IfErrors+3
FileSeek$9 0 END $R6
FileClose$9
StrCmp$5 '' +2
IntCmp $R6$5 0 FileFunc_GetSize_findnext
StrCmp$6 '' +2
IntCmp $R6$6 0 0 FileFunc_GetSize_findnext
IntOp $R4 $R4+ 1
; insert code
IntOp $R6 $R6+ 4096
IntOp $R1 $R6% 4096
StrCmp $R1 0 0+2
StrCpy $R1 4096
IntOp $R2 4096- $R1
IntOp $R6 $R6- 4096
IntOp $R6 $R6+ $R2
; end insert
System
::Int64Op $R3 + $R6
Pop $R3

>...

Pop $R4
Pop $R3
; insert code
Pop $R2
Pop $R1
; end insert
Pop$9
Pop$8

>...
Size on disk is valid on NTFS formatted drives. All credit for the original "GetSize" goes to KichiK -- Function "FindFiles".

For Windows XP, I found that the only way to make Add/Remove display the estimated size was to also write the DWORD "WindowsInstaller" 1 - then it shows up. I don't know what other consequences are of setting that DWORD as we just discovered it a few minutes ago and are still testing.

edit: Dammit, now the presense of "WindowsInstaller" 1 is preventing the entry from showing entirely. Why is this so convoluted?


Is there any solution?
I write all uninstall information in HKLM ...\Uninstall. But it doesn't appear in Add/Remove software.
I use Windows XP SP2.
I read all information, but i don't get it. Has someone a clear solution?`
Thx


Did you miss the last post?

Stu


You should not be setting WindowsInstaller=1, it is a undocumented value and we don't know what it does


!DISCLAIMER!
This data is based on an undocumented registry entry and is only verified on Windows XP and is subject to change.
In Addition, the example only lists 32bit installations unless you tweak it to read from the 64bit registry.


Here's what I know...

Add and Remove Programs dialog lists the Size based from the corresponding ArpCache registry entry.

for example here is the my machines Notepad++ ArpCache Entry


Windows Registry Editor Version 5.00


>***91;HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionApp ManagementARPCacheNotepad++***93;
>"SlowInfoCache"=hex:28,02,00,00,01,00,00,00,00,50,ae,00,00,00,00,00,64,22,d7,
82,ab,ae,cb,01,00,00,00,00,43,00,3a,00,5c,00,50,00,72,00,6f,00,67,00,72,00,
61,00,6d,00,20,00,46,00,69,00,6c,00,65,00,73,00,5c,00,4e,00,6f,00,74,00,65,
00,70,00,61,00,64,00,2b,00,2b,00,5c,00,6e,00,6f,00,74,00,65,00,70,00,61,00,
64,00,2b,00,2b,00,2e,00,65,00,78,00,65,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
00,00,00,00,00,00,00,00
>"Changed"=dword:00000000
>
The important entry here is the "SlowInfoCache" value.

There is a pretty good and short article explaining it here: http://www.pcmag.com/article2/0,2817,1173443,00.asp

Here is an example of reading the data:


"LogicLib.nsh"


>OutFile Test.exe
ShowInstDetails show

Section
## Open Registry Key
System::Call "Advapi32::RegOpenKeyEx(i 0x80000002,t 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache\Notepad++',i 0,i 1,*i .r0)i .r3"
;DetailPrint "Result=$3"
${IfNotThen} $3 = 0 ${|} Abort "Not ARPCache data is available." ${|}

## Check for existance of SlowInfoCache and validate tpye and size
System::Call "Advapi32::RegQueryValueEx(i r0,t 'SlowInfoCache',i 0,*i .r4,i 0,*i .r5)"
${IfNotThen} $3 = 0 ${|} Abort "Not SlowInfoCache data is available." ${|}
${
IfNotThen} $4 = 3 ${|} Abort "SlowInfoCache type is unexpected" ${|}
${IfNotThen} $5 = 552 ${|} Abort "SlowInfoCache size unexpected" ${|}

## Read SlowInfoCache Data
System::Alloc $5
Pop$6
System::Call "Advapi32::RegQueryValueEx(i r0,t 'SlowInfoCache',i 0,*i n,i r6,*i r5)"
${IfNotThen} $3 = 0 ${|} Abort "Error reading SlowInfoCache data" ${|}
System::Call '*$6(&i4 .R1,&i4.R2,&i8.R3,&i4 .s,&i4 .s,&i4 .R5,&w524 .R6)'

## Convert the LastUsed FileTime to a Human readable format
System::Call `*(&i4 s,&i4 s)i .r7`
System::Free $6

System::Call "*(&i2, &i2, &i2, &i2, &i2, &i2, &i2, &i2) i .r3"
System::Call "Kernel32::FileTimeToSystemTime(i $7, i r3)"
System::Call "Kernel32::GetDateFormatA(i 0,i 0,i r3,t 'MM/dd/yyyy',t .R4,i ${NSIS_MAX_STRLEN})"
System::Free $7

## Close Registry Key
System::Call "Advapi32::RegCloseKey(i r0)i .r3"
${IfNotThen} $3 = 0 ${|} Abort "Unable to close registry key" ${|}

## Format the InstallSize into a human readable format ***91;bytes to megabytes***93;
Math::Script "R3=ff(R3/1048576.0,18)+' MB'"

## Display Results
DetailPrint "cbSize=$R1"
DetailPrint "HasName=$R2"
DetailPrint "InstallSize=$R3"
DetailPrint "LastUsed=$R4"
DetailPrint "Frequency=$R5"
DetailPrint "Name=$R6"
>SectionEnd
>
The Frequency value is an indication of the times the program is executed from a traceable shortcut from the Start Menu or Desktop. On the Add & Remove Programs dialog this is expressed as "Rarely", "Occasionally", or "Frequently". I'm not sure what values trigger what title but It could be calculated by tweaking a know value by increments. I think this is also tied to the LastUsed date so it might not be as simple hard value ranges.

Yep, the code KEYofR posted works (for me too) under win 7.

here is it again:


!include "TextFunc.nsh"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0 #< conv to DWORD
WriteRegDWORD ${APP_UNINST_ROOT_KEY} "${APP_UNINST_KEY}" "EstimatedSize" "$0"


Later, in few days, I will test it on XP also.

Thanks

Originally posted by imgarfield
Yep, the code KEYofR posted works (for me too) under win 7.

here is it again:


!include "TextFunc.nsh"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0 #< conv to DWORD
WriteRegDWORD ${APP_UNINST_ROOT_KEY} "${APP_UNINST_KEY}" "EstimatedSize" "$0"


Later, in few days, I will test it on XP also.

Thanks
It seems to work under XP also.

On the subject again.

Putting the size in the registry is one thing, getting the correct size is another.

The Required Space, I think, is calculated at compile-time based on the section sizes. You could query SectionGetSize ${id} $0, and the value returned would be a similar figure in Kb.

Is it size on disk? Size on disk is determined by the cluster size, which is your cluster size at compile-time.

If you want to replace the NSIS estimate with your own more accurate size estimate, should it be size on disk (in Kb), your disk, or should it be derived from bytes? The same question when you write the size to the registry, bytes or size on disk?

I would like to use size on disk.

My questions are, a) what does the NSIS (section size) estimate use? b) can you get the cluster size in a system call? GetVolumeInformation "Kernel32:: ... ?

Can anyone help? Thanks.


It occurs to me that the easiest way to find out the cluster size would be to write a 1 byte file and have the system tell you the size on disk. Only the system won't tell you. It'll tell you the file is 1 byte.

Is that correct?


NSIS (and most other programs) don't handle cluster size/on disk size at all.

What if the destination directory is compressed? One of the files already exists and is sparse?


You'd need that information too. Target compression as well as cluster size.

Also, if the cluster size is wrong, 8Kb instead of 4Kb, for instance, or if the destination is compressed, would the size-used estimate be more or less accurate than the bytes value?

I have never dealt with a compressed folder for an installation; I honestly don't know what happens. In case the folder is compressed, you could always revert to bytes, I'd say.

The user wants to know how much space a program takes up to avoid running out of space among other reasons, no doubt. Size on disk gives an accurate picture, provided it is accurate.

Do I withdraw the question?


Unlike NSIS and most programs I'm willing to gamble on compression, sparse files ... if it isn't too much trouble.

Cluster size?

I read about cluster size that it's hidden somewhere deep. :bin: Googled.


#!define LOGICAL ; "Space required" by the setup is calculated in bytes or physical size
; When LOGICAL is defined the logical size or the size on disk is calculated; to return an
; accurate value, the target volume has to be formatted in 4KB blocks
Skip down to the next code:

!macro INI_READ KEY
!ifdef LOGICAL
ReadIniStr $3 ${TEMP1} "LOGICAL" "${KEY}"
!else
ReadIniStr $3 ${TEMP1} "PHYSICAL" "${KEY}"
!endif
!macroend
The ini file has two corresponding sections:

[LOGICAL]
X=4
A=264
W=276
Q=8
All=23048
Win7=-2940
Win7N=-2940
WinV=-112
WinVN=-196
[PHYSICAL]
X=16
A=266696
W=281943
Q=4945
All=22044535
Win7=-3007822
Win7N=-3007811
WinV=-100856
WinVN=-195667
Getting the logical size (4KB) requires a modified version of KichiK's GetSize function/macro. I generate the ini file before compiling the setup.

I have one section for "Required space":

SectionSetSize ${id1} 0 ; reset size estimate
SectionSetSize ${id2} $SIZE_2 ; the new size in KiB
The section id1 contains the install files. The id2 section is otherwise empty.

For the registry I do exactly what the previous posters described:

SectionGetSize ${id2} ${TEMP1}
IntFmt ${TEMP1} "0x%08X" ${TEMP1}
WriteRegDword HKLM ${PRODUCT_UNINST_KEY} "EstimatedSize" ${TEMP1}
It hinges on cluster size. Without some means to test for it, LOGICAL must stay a pipe dream.

Everything is illogical.

Sorry to keep bumping this thread.

I have made some headway and still have questions. Maybe someone can help.

I'm thinking of doing an NTFS check first.

StrCpy $0 $WINDIR 3 ; system drive
${GetFileSystem} $0 $0
${If} $0 == "NTFS"

I could proceed to checking the cluster size.

System::Call 'kernel32::GetDiskFreeSpace(i0,*i0r1,*i0r0,*i0r2,*i)'

Multiplying $0 * $1 does that. To be on the safe side, I'm making NTFS a condition, though GetDiskFreeSpace should work on older Windows and FAT systems.

This is where I have questions. Anders mentioned folder compression. Is folder compression something you can detect? What actually are the disk space consequences?

Sparse files, also mentioned, are probably less of a concern. Why would anyone wish to convert the files my setup installs into sparse files?

AFAIK, sparse files are used for disk images and p2p sharing. Is reinstalling possible?

Could someone push me in the right direction for folder compression? The fact it was raised lets me suspect that a solution is not easily come by.

Can you check if the destination directory is compressed?

I would really appreciate a yes or a no. Instructions wouldn't be bad either. Thanks.


To detect compression you can just check the file attribute...


The best I can do.

On the Directory page I can do a check for compression and, if compressed, the "Required space" changes to physical size, even if the other conditions for logical size are met.

However, if the user chooses to install to a new folder, meanwhile leaving the compressed folder alone, a second installation to the new folder, the "Required space" won't change back to logical size until after the user exits the page.

Only on clicking the Back button and returning to the Directory page would the user be aware of the new (old) size.

It's a small glitch, but one that's impossible to fix, unless I disallow multiple installations.

It seems almost better to stick with the original plan: always display logical size regardless of compression or not.

Compressed directories and sparse files have given me something to consider, and I am grateful for your advice, Anders.:)


And thanks for GetFileAttributes.