I'm writing an installer for Windows application. I'm using MUI for NSIS. One of the pages of the installer is Directory Page, where I have the "Space required" field. The problem is that the space required is always 0.0KB.
I was looking for some answers, but all I found was that space is calculated automatically. I wonder if there is some way to check which folder size this macro gets? Or any other ideas?
;Pages
; Installation
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "#CPACK_RESOURCE_FILE_LICENSE#"
!insertmacro MUI_PAGE_DIRECTORY
Page custom pgAppLanguageCreate
The size is automatically calculated by the File instructions in Sections plus any extra you add with AddSize.
If you are not happy with this calculation you can force a specific size in .onInit with SectionSetSize.
I found what causes the problem.
In the "Installer Section" I used a function that copies all files.
Instead of calling it here, I just paste the entire function and now that works. It looks like you cant use "File" instruction in function because it doesn't add size to the required space this way.
If you use it in section, it works perfectly.
; Installer Sections
Section "install" Install
${If} $instState != "1"
Call deleteAllFiles
Call deleteInfoFromRegistry
Call deleteShortcut
${EndIf}
SetOutPath "$INSTDIR"
; copy files
File ${ICON}
File "slicer_license"
File /r "${INSTALL_FILE}\package\"
;File "README.txt" ;Readme file.
Call createShortcut
Call addInfoToRegistry
Call setAppLanguageShortcut
Call createLanguageFile
SectionEnd
Related
I am porting our NSI installer to Linux and Mac instead of Windows to better integrate with our Maven build system.
We need to sign our installer and uninstaller. This was done as suggested at http://nsis.sourceforge.net/Signing_an_Uninstaller, but I just realized that it tries to run the tempinstaller to force it to produce the uninstaller.exe which can then be signed.
Obviously this trick doesn't work too well on *Nix systems and make this part of the process non-portable.
Does anyone has a better solution. I'm no expert at NSIS and wondering if there is a clever way to get the uninstall.exe so that it can be signed?
I don't think there is a real solution to this.
The installer and uninstaller uses the same exe code and only checks a flag (FH_FLAGS_UNINSTALL in firstheader) on startup to see if it is a uninstaller. Just flipping this bit is not enough though, the program would fail the CRC check and even if you bypass that the uninstaller data is compressed so you would have to decompress that to the correct location in the file. To actually accomplish this you would have to write a custom tool. You can see this operation in the NSIS source in exec.c if you search for EW_WRITEUNINSTALLER.
We need to sign our installer and uninstaller. This was done as suggested at http://nsis.sourceforge.net/Signing_an_Uninstaller, but I just realized that it tries to run the tempinstaller to force it to produce the uninstaller.exe which can then be signed. [...] this trick doesn't work too well on *Nix systems and make this part of the process non-portable.
If you exploit a stub installer for uninstall operations (no payload), this appears to be possible.
It will spawn an uninstall.exe process from the $TEMP folder, which is then capable of deleting $INSTDIR.
This script will create a stub (un)installer which can then be Authenticode Signed. It will compile on Windows, MacOS and Linux.
Caveats:
You'll have to manually bundle this into the installer (trivial)
You'll have to manage your own uninstall registry entries (trivial)
The look and feel may not match NSIS's default for uninstallers
You'll see the installer open twice (first from $INSTDIR, second from $TEMP). This is a child process which allows uninstall.exe to delete itself, similar to how NSIS does it in the Section "Uninstall".
You'll need a secondary .nsi script dedicated to uninstall operations, cumbersome if you have a lot of shared logic between your install/uninstall sections.
Worse, you'll have to AVOID the "Uninstall" section title, as you'll be placed into the same problem as the OP when that bytecode is generated.
When explicitly running from $TEMP some relative file logic will be incorrect. The example passes these back in as a $DELETE_DIR, $DELETE_EXE respectively.
The code:
!include MUI2.nsh
!include x64.nsh
!include LogicLib.nsh
!include FileFunc.nsh
!include WinMessages.nsh
!define MUI_PRODUCT "My App"
!define MUI_VERSION "1.0.0"
; Masquerade the title
!define MUI_PAGE_HEADER_TEXT "Uninstall My App"
!define MUI_PAGE_HEADER_SUBTEXT "Remove My App from your computer"
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Uninstallation Complete"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "Uninstall was completed successfully."
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro GetParameters
RequestExecutionLevel admin
CRCCheck On
OutFile "uninstall.exe"
Name "Uninstall"
Var /GLOBAL RESPAWN
Var /GLOBAL DELETE_DIR
Var /GLOBAL DELETE_EXE
Section
; Masquerade as uninstall
SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:Uninstall"
${GetParameters} $0
${GetOptions} "$0" "/RESPAWN=" $RESPAWN
${GetOptions} "$0" "/DELETE_DIR=" $DELETE_DIR
${GetOptions} "$0" "/DELETE_EXE=" $DELETE_EXE
${If} $RESPAWN != ""
; We're running from $TEMP; Perform the uninstall
!define yay "We're running from $EXEPATH, yay, we can remove the install directory!$\n$\n"
!define myvars "$\tRESPAWN$\t$RESPAWN$\n$\tDELETE_EXE$\t$DELETE_EXE$\n$\tDELETE_DIR$\t$DELETE_DIR"
MessageBox MB_OK "${yay}${myvars}"
; Your uninstall code goes here
; RMDir /r $DELETE_DIR\*.*
; Delete "$DESKTOP\${MUI_PRODUCT}.lnk"
; Delete "$SMPROGRAMS\${MUI_PRODUCT}\*.*"
; RmDir "$SMPROGRAMS\${MUI_PRODUCT}"
; Delete Uninstaller And Unistall Registry Entries
; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${MUI_PRODUCT}"
; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}"
; Remove the old version of ourself
ClearErrors
Delete $DELETE_EXE
IfErrors 0 +3
MessageBox MB_OK "File could NOT be deleted: $DELETE_EXE"
Goto +2
MessageBox MB_OK "File was successfully deleted: $DELETE_EXE"
; Remove ourself from $TEMP after reboot
Delete /REBOOTOK $EXEPATH
; ${If} ${RunningX64}
; ${EnableX64FSRedirection}
; ${EndIf}
SetDetailsPrint textonly
DetailPrint "Completed"
${Else}
; We're NOT running from $TEMP, copy to temp and respawn ourself
GetTempFileName $0
CopyFiles "$EXEPATH" "$0"
Exec '"$0" /RESPAWN=1 /DELETE_DIR="$EXEDIR" /DELETE_EXE="$EXEPATH"'
Quit
${EndIf}
SectionEnd
Function .onInit
; ${If} ${RunningX64}
; SetRegView 64
; ${DisableX64FSRedirection}
; ${EndIf}
FunctionEnd
I have created Exe file for my app using NSIS script.In my script i have checked free space for selected directory.
1.If selected directory dont have required space then user wants to change the directory.
2.After changing directory in directory page again wants to check free space.so when the required space is available for the selected directory then only proceed to next page.
So it will come under looping statement.I have tried following script
page custom checking
Function checking
Push "\"
push $InstallDir
Call SplitFirstStrPart
pop $R0
${DriveSpace} $R0 "/D=F /S=G" $R0
${While} $R0 <= 2
MessageBox MB_OK "Expected free space is not availble"
call directory
${EndWhile}
Function directory
--Here i want to define directory page--
[page directory] we cant use this here
call checking
FunctionEnd
1.How to create user defined directory page?
2.Is possible to call page directory or MUI_PAGE_DIRECTORY multiple times?
Thanks
You cannot call a page from a function but you can skip a page by calling Abort in the page PRE callback and you can also jump to any page.
You can have multiple pages of all page types:
!include MUI.nsh
Var dir1
Var dir2
Function .onInit
StrCpy $dir1 c:\default1
StrCpy $dir2 c:\default2
FunctionEnd
!define MUI_DIRECTORYPAGE_VARIABLE $dir1
!insertmacro MUI_PAGE_DIRECTORY
!define MUI_DIRECTORYPAGE_VARIABLE $dir2
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE English
Section
DetailPrint $dir1
DetailPrint $dir2
SectionEnd
probably I am not getting basics of pages and sections in nsis script.
I have to analyse installation script which was not made by me. In the top of the script there are macros of MUI pages for example
!insertmacro MUI_PAGE_LICENSE $(license)
!insertmacro MUI_PAGE_INSTFILES ....
And then further down the code there are sections
Section "MainSection" SEC01
SetShellVarContext current
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
File "${xy_TEMP_SRC}\InstallSrc\xy.exe"
File "${xy_TEMP_SRC}\InstallSrc\xy.exe.config"
SetOutPath "$INSTDIR\sk"
File "${xy_TEMP_SRC}\InstallSrc\sk\xy.resources.dll"
SetOutPath "$INSTDIR"
CreateDirectory "$SMPROGRAMS\xy"
CreateShortCut "$SMPROGRAMS\xy\xy.lnk" "$INSTDIR\xy.exe"
CreateShortCut "$DESKTOP\xy.lnk" "$INSTDIR\xy.exe"
SectionEnd
+ another sections for instance unninstall section
My question is how and when the sections are executed when there is no reference from pages to the sections.
My brain is telling me that the sections should be executed sometimes during the pages confirmation during the installation process, but I guess it's wrong, so please can anyone tell me how it actualy works?
All sections are executed on the instfiles page and in the order of your sections. If you need stuff to be executed before, after or in between, you can use functions (e.g. pre- or leave functions)
!insertmacro MUI_PAGE_INSTFILES Execute the sections.
I have 4 programs that I'd like to package into one installer and allow the user to select which one they would like to install.
I've never used NSIS before but I was recommended to give it a shot, however, I've no idea where to begin with this.
Basically I just need one page that asks the user to select a radio button then click next to install one of the following programs:
-- Install components --------------------
Select a program from the list below and
click Next to continue.
O Program 1
O Program 2
O Program 3
O Program 4
-------------------------------------------
Cancel Next
Then depending on what they choose it launches program1_setup.exe or program2_setup.exe etc.
As each of my 4 programs are installers in their own right, I take it I don't need to set up the uninstall script in NSIS as that's taken care of already?
Thanks,
Greg.
This code is similar to the one-section.nsi example.
...
!include sections.nsh
Page components
Page instfiles
Section /o "Program 1" P1
File "/oname=$pluginsdir\Setup.exe" "myfiles\Setup1.exe"
SectionEnd
Section "Program 2" P2
File "/oname=$pluginsdir\Setup.exe" "myfiles\Setup2.exe"
SectionEnd
Section ; Hidden section that runs the show
DetailPrint "Installing selected application..."
SetDetailsPrint none
ExecWait '"$pluginsdir\Setup.exe"'
SetDetailsPrint lastused
SectionEnd
Function .onInit
Initpluginsdir ; Make sure $pluginsdir exists
StrCpy $1 ${P2} ;The default
FunctionEnd
Function .onSelChange
!insertmacro StartRadioButtons $1
!insertmacro RadioButton ${P1}
!insertmacro RadioButton ${P2}
!insertmacro EndRadioButtons
FunctionEnd
You can use the CheckBitmap attribute to change the checkbox icons if you want...
Do I need to include a specific .nsh library or function definition to use the function 'StrContains' in NSIS?
I have looked for a download for the library but I cant seem to find it?
When I go to compile this code I get the compile error: "Invalid command: ${StrContains}"
!include "LogicLib.nsh"
# Compile error below
!macro test
${StrContains} $0 $1 "abc"
!macroend
Section
DetailPrint ""
SectionEnd
You need to add the function definition shown in the StrContains function page of the NSIS wiki (in the category of strings functions) in your code.
Don't forget the last statement !define StrContains ... to be able to call it with ${StrContains}