Getting a path for each component in NSIS - windows

I'm trying to create an installer with NSIS that installs 3 different components to three different paths. I want the users to select/confirm each of them, but they should only be asked if they've selected the relevant component.
Since pages can't appear in sections, I'm at a loss how to do this
Any suggestions?
Thanks in advance :-)

You can use multiple directory pages:
!include LogicLib.nsh
InstallDir $ProgramFiles32\Foo\Bar
Var Comp1Path
Var Comp2Path
Page Components
PageEx Directory
DirText "Blah blah 1"
DirVar $Comp1Path
PageCallbacks Comp1Pre
PageExEnd
PageEx Directory
DirText "Blah blah 2"
DirVar $Comp2Path
PageCallbacks Comp2Pre
PageExEnd
Page InstFiles
Section /o Comp1 SID_C1
DetailPrint "Installing Comp1 to $Comp1Path"
SectionEnd
Section Comp2 SID_C2
DetailPrint "Installing Comp2 to $Comp2Path"
SectionEnd
Function Comp1Pre
StrCpy $Comp1Path $InstDir\Comp1
${IfNot} ${SectionIsSelected} ${SID_C1}
Abort ; Skipping this page
${EndIf}
FunctionEnd
Function Comp2Pre
StrCpy $Comp2Path $InstDir\Comp2
${IfNot} ${SectionIsSelected} ${SID_C2}
Abort
${EndIf}
FunctionEnd
; In this example the next button on the components page might be the last page before InstFiles so we have to update the button text
!include WinMessages.nsh
Function .onSelChange
GetDlgItem $1 $hwndParent 1
${If} ${SectionIsSelected} ${SID_C1}
${OrIf} ${SectionIsSelected} ${SID_C2}
SendMessage $1 ${WM_SETTEXT} 0 "STR:$(^NextBtn)"
${Else}
SendMessage $1 ${WM_SETTEXT} 0 "STR:$(^InstallBtn)"
${EndIf}
FunctionEnd
Another alternative would be to create a custom page with nsDialogs and just disable or hide the text fields the user does not need to confirm...

Related

NSIS: Componesnts page on component checked event

I using NSIS to install my project. I need to show MessageBox with warning text, when I choosing some section to install on components page. Is there some way to track the click on the checkbox, may be event or something?
Use the .onSelChange callback.
In NSIS 3 the changed section id is stored in $0:
Page Components
Page InstFiles
Section /o "Foo" SID_FOO
SectionEnd
Section "Bar"
SectionEnd
!include LogicLib.nsh
Function .onSelChange
${If} ${SectionIsSelected} ${SID_FOO}
${AndIf} $0 = ${SID_FOO}
MessageBox MB_ICONEXCLAMATION "Warning, section Foo selected!"
${EndIf}
FunctionEnd
You have to track the state yourself in NSIS 2:
Page Components
Page InstFiles
Section /o "Foo" SID_FOO
SectionEnd
Section "Bar"
SectionEnd
!include LogicLib.nsh
Var hasWarned
Function .onSelChange
${If} ${SectionIsSelected} ${SID_FOO}
${AndIf} $hasWarned = 0
StrCpy $hasWarned 1
MessageBox MB_ICONEXCLAMATION "Warning, section Foo selected!"
${EndIf}
/* Uncomment this to display the warning every time it is selected
${IfNot} ${SectionIsSelected} ${SID_FOO}
StrCpy $hasWarned 0
${EndIf}
*/
FunctionEnd

NSIS Install like in TeamViewer (Portable mode option)

What I basically want is TeamViewer-like first page for my NSIS installer with the following options:
3 radio buttons for: Run Only; Install for current user; Install for all users (requires restart with admin rights).
A label for license like in TeamViewer (i.e. no actual EULA page, only a link to it in the footer).
A button that can change text, i.e. Accept and Run or Accept and Install.
I cannot figure out how to do it easily in terms of UI and in terms of control flow.
Also I need the ability to restart the installer if user decides to install program for all users (i.e. I guess there should be a detectable command line switch, so that if present installer will automatically assume 3rd install type).
A screenshot of a sample UI as requested:
A sample NSIS template would be greatly appreciated.
Thanks.
...
RequestExecutionLevel user
!include LogicLib.nsh
!include nsDialogs.nsh
!include FileFunc.nsh
!include MUI2.nsh
Var mode
Var modeRadioRun
Var modeRadioInstCU
Var modeRadioInstLM
Function OnRadioChange
GetDlgItem $1 $hwndparent 1 ; Find Install/Next button
${NSD_GetState} $modeRadioRun $0
${If} $0 = ${BST_CHECKED}
${NSD_SetText} $1 "Accept && Run"
${Else}
${NSD_SetText} $1 "Accept && Install"
${EndIf}
FunctionEnd
Function ModePageCreate
!insertmacro MUI_HEADER_TEXT "Welcome to blah" "blah blah"
${GetParameters} $0
ClearErrors
${GetOptions} "$0" "/ELEVATEDINSTALL" $0
${IfNot} ${Errors}
UserInfo::GetAccountType
Pop $0
${If} $0 == "Admin"
StrCpy $mode 1
Abort ; Skip page and start installing
${Else}
MessageBox mb_iconstop "Admin rights required!"
${EndIf}
${EndIf}
nsDialogs::Create 1018
Pop $0
${NSD_CreateRadioButton} 30u 20u 50% 12u "Run"
Pop $modeRadioRun
${NSD_OnClick} $modeRadioRun OnRadioChange
${NSD_CreateRadioButton} 30u 40u 50% 12u "Install for current user"
Pop $modeRadioInstCU
${NSD_OnClick} $modeRadioInstCU OnRadioChange
${NSD_CreateRadioButton} 30u 60u 50% 12u "Install for all users"
Pop $modeRadioInstLM
${NSD_OnClick} $modeRadioInstLM OnRadioChange
${NSD_CreateLink} 20u -14u 50% 12u "License"
Pop $0
${NSD_OnClick} $0 ShowLicense
${NSD_Check} $modeRadioRun
call OnRadioChange ; Trigger button change
nsDialogs::Show
FunctionEnd
Function ModePageLeave
${NSD_GetState} $modeRadioRun $0
${NSD_GetState} $modeRadioInstCU $1
${If} $0 = ${BST_CHECKED}
InitPluginsDir
SetOutPath $pluginsdir
File "myapp.exe"
ExecWait '"$pluginsdir\myapp.exe"'
SetOutPath $temp ; Don't lock $pluginsdir
Quit
${ElseIf} $1 = ${BST_CHECKED}
StrCpy $mode 0
${Else}
StrCpy $mode 1
UserInfo::GetAccountType
Pop $0
${If} $0 != "Admin"
ExecShell "runas" '"$exepath"' "/ELEVATEDINSTALL"
Quit
${EndIf}
${EndIf}
FunctionEnd
Function ShowLicense
ExecShell "" "http://example.com/license"
FunctionEnd
Page Custom ModePageCreate ModePageLeave
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section
${If} $mode > 0
SetShellVarContext all
StrCpy $InstDir "$ProgramFiles\MyApp"
${Else}
SetShellVarContext current
StrCpy $InstDir "$LocalAppData\Programs\MyApp"
${EndIf}
SetOutPath $InstDir
File myapp.exe
CreateShortcut "$SMPrograms\MyApp.lnk" "$InstDir\myapp.exe"
WriteUninstaller "$InstDir\Uninst.exe"
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyAppGuid" "UninstallString" '"$InstDir\Uninst.exe"'
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyAppGuid" "DisplayName" "MyApp blah blah"
SectionEnd
Section Uninstall
; Todo: Remove files and registry entries (You should write to a .ini in $InstDir so you know if it was a per user or machine install)
RMDir "$InstDir"
SectionEnd
You might want to edit the base UI to make the install button larger with Resource Hacker (on one of the files in NSIS\Contrib\UIs) and in the script use ChangeUI to apply.

Disable two mutually exclusive Sections when SectionGroup unchecked?

I have an NSIS installer script with two SectionGroups. Each SectionGroup has two Sections, which are mutually exclusive.
I need to have the user able to uncheck the SectionGroup, which unchecks and disables ("grays-out") the Sections. Basically the user can choose to install one of the Sections, or none. On top of that, the second SectionGroup must be disabled if the first SectionGroup is unchecked.
I'm using this script as reference to control the mutually exclusive Sections: http://nsis.sourceforge.net/Mutually_Exclusive_Sections
Thanks in advance.
Your disable/gray requirement does not make sense. If you click the section group again to enable the "child sections", which of the two gets checked? And you would only be able to get out of the disabled state by clicking the group itself so I did not implement it.
In general, anything beyond simple radio button behavior gets complicated quickly. If you are using the 3.0 alpha version of NSIS then .onSelChange will actually tell you which item that changed which would make this less complicated...
Page Components "" SaveState
Page Instfiles
!include sections.nsh
!include logiclib.nsh
SectionGroup /e "Grp1" GRP_1
Section "A" SEC_A
SectionEnd
Section /o "B" SEC_B
SectionEnd
SectionGroupEnd
SectionGroup /e "Grp2" GRP_2
Section /o "C" SEC_C
SectionEnd
Section "D" SEC_D
SectionEnd
SectionGroupEnd
; Remove comments for a different behavior
Function SaveState
!macro SaveSel id var
SectionGetFlags ${id} ${var}
IntOp ${var} ${var} & ${SF_SELECTED}
!macroend
#SectionGetFlags ${GRP_1} $R0
!insertmacro SaveSel ${SEC_A} $R1
!insertmacro SaveSel ${SEC_B} $R2
#SectionGetFlags ${GRP_2} $R3
!insertmacro SaveSel ${SEC_C} $R4
!insertmacro SaveSel ${SEC_D} $R5
FunctionEnd
Function .onSelChange
!macro OneOfTwoItemsInAGroup gid gv i1 v1 i2 v2
#SectionGetFlags ${gid} $0
!insertmacro SaveSel ${i1} $1
!insertmacro SaveSel ${i2} $2
${If} $1 <> 0
${AndIf} $2 <> 0
StrCpy $1 ${i1}
${IfThen} ${v1} = 0 ${|} StrCpy $1 ${i2} ${|}
!insertmacro UnselectSection $1
/*${If} ${gv} = $0
!insertmacro UnselectSection ${gid}
${EndIf}*/
${EndIf}
!macroend
!insertmacro OneOfTwoItemsInAGroup ${GRP_1} $R0 ${SEC_A} $R1 ${SEC_B} $R2
!insertmacro OneOfTwoItemsInAGroup ${GRP_2} $R3 ${SEC_C} $R4 ${SEC_D} $R5
Call SaveState
FunctionEnd

Disable 'next' button on the component page when there are no selected components

I'm using NSIS 2.46 to create a installer for my windows application, I have a component page with 12 checkboxes, that is 12 sections in my NSIS code, now I want to disable the 'Next' button if none of the sections are checked by the user, I'm using this code:
Somehow it doesn't accept R registers above R9...
SectionGetFlags ${section11} $R10
SectionGetFlags ${section12} $R11
The compiler error I'm getting is
Please tell me how to disable the 'Next' button if there are more than 10 components...
The basic NSIS registers are $0...$9 and $R0...$R9, so you should use $1 and $2 for the last two sections. Or you can create more variables if you want; Var /GLOBAL R10.
If section1 to section12 are numbered without gaps you can use a loop:
!include LogicLib.nsh
Section A S_1
SectionEnd
Section /o B S_2
SectionEnd
Section C S_3
SectionEnd
Function .onSelChange
StrCpy $0 0
StrCpy $1 ${S_1}
${DoWhile} $1 <= ${S_3}
${If} ${SectionIsSelected} $1
StrCpy $0 1
${ExitDo}
${EndIf}
IntOp $1 $1 + 1
${Loop}
GetDlgItem $1 $HwndParent 1
EnableWindow $1 $0
FunctionEnd

using nsis installer, adding custom radiobuttons, calling sections according to radiobutton chosen

I want that if none of the RadioButtons are selected , then ,when the Next button is pressed, then it should give an alert that PLEASE CHOSE ATLEAST ONE ITEM, and it should not go to the next Dialog.
Also, I want that if the user selects the option : UPDATE EXISTING SOFTWARE, then only some files are copied, and if the other radiobutton is selected , then all files are copied,
Is this possible using sections or functions have to be used? can i call a Section, like if RadioButton 1 is chosen, then SECTION CREATEALLFILES is called, else SECTION CREATEONLYTWOFILES is called?
According to me, i think i want the code to HOW TO HOLD THE ids of these two RadioButtons and use them accordingly , to call different sections or functions. What would be the code? Please help?
Also, after pressing NEXT on this page, the next dialog will come as in image below: i want to show a LABEL , whether DEMO is done, or UPDATE is running, for this i will add a Label using Resource Hacker, but how to display that Label and hide it according to user choice of RadioButton
You can select/unselect sections or just put the logic in a single section, this example does both:
!include nsDialogs.nsh
!include Sections.nsh
var InstallType
Section
#Install common files...
${If} $InstallType == DEMO
#Do demo specific stuff
${Else}
#Do update specific stuff
${EndIf}
SectionEnd
Section "" SEC_DEMO
#Install demo..
SectionEnd
Section "" SEC_UPDATE
#Do update..
SectionEnd
Page custom InstTypePageCreate InstTypePageLeave
Function InstTypePageCreate
nsDialogs::Create 1018
pop $0
${NSD_CreateRadioButton} 0 50u 100% 10u "Demo"
pop $1
${IfThen} $InstallType == DEMO ${|} ${NSD_Check} $1 ${|}
${NSD_CreateRadioButton} 0 70u 100% 10u "Update"
pop $2
${IfThen} $InstallType == UPDATE ${|} ${NSD_Check} $2 ${|}
nsDialogs::Show
FunctionEnd
Function InstTypePageLeave
${NSD_GetState} $1 $0
${If} $0 = ${BST_CHECKED}
StrCpy $InstallType DEMO
!insertmacro UnselectSection ${SEC_UPDATE}
!insertmacro SelectSection ${SEC_DEMO}
${Else}
${NSD_GetState} $2 $0
${If} $0 = ${BST_CHECKED}
StrCpy $InstallType UPDATE
!insertmacro UnselectSection ${SEC_DEMO}
!insertmacro SelectSection ${SEC_UPDATE}
${Else}
MessageBox MB_ICONSTOP "You must select something!"
Abort
${EndIf}
${EndIf}
FunctionEnd
To set the text on the next page, just use ${NSD_SetText} $hwndYourLabel "Text" and ShowWindow inside a if block that tests $InstallType (This code needs to be in the show function callback (MUI_PAGE_CUSTOMFUNCTION_SHOW) for that page)

Resources