Two installations in one installer: Difference between revisions
From NSIS Wiki
Jump to navigationJump to search
m (Added category links.) |
(Fix silent installers) |
||
(12 intermediate revisions by 9 users not shown) | |||
Line 1: | Line 1: | ||
{{PageAuthor|Afrow UK}} | |||
== Description == | == Description == | ||
This script shows how we can install two programs with one installer, where each program has its own Directory and InstFiles page. Obviously we still have the single Components page though, as if we chose to have two then we'd might as well make two | This script shows how we can install two programs with one installer, where each program has its own Directory and InstFiles page. Obviously we still have the single Components page though, as if we chose to have two then we'd might as well make two installer exe's! | ||
== The Script == | == The Script == | ||
Here's the code. You can compile this script straight off. | Here's the code. You can compile this script straight off. I've added MessageBox's to test it. | ||
<highlight-nsis> | <highlight-nsis> | ||
Name "Multiple InstFiles" | Name "Multiple InstFiles" | ||
Line 21: | Line 19: | ||
!insertmacro MUI_PAGE_WELCOME | !insertmacro MUI_PAGE_WELCOME | ||
!define MUI_PAGE_CUSTOMFUNCTION_PRE | !define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesCheck | ||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave | !define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave | ||
!insertmacro MUI_PAGE_COMPONENTS | !insertmacro MUI_PAGE_COMPONENTS | ||
## This is the title on the first Directory page | ## This is the title on the first Directory page | ||
!define MUI_DIRECTORYPAGE_TEXT_TOP " | !define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_A)" | ||
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesA | !define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesA | ||
!insertmacro MUI_PAGE_DIRECTORY | !insertmacro MUI_PAGE_DIRECTORY | ||
!insertmacro MUI_PAGE_INSTFILES | !insertmacro MUI_PAGE_INSTFILES | ||
## This is the title on the second Directory page | ## This is the title on the second Directory page | ||
!define MUI_DIRECTORYPAGE_TEXT_TOP " | !define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_B)" | ||
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesB | !define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesB | ||
!insertmacro MUI_PAGE_DIRECTORY | !insertmacro MUI_PAGE_DIRECTORY | ||
!insertmacro MUI_PAGE_INSTFILES | !insertmacro MUI_PAGE_INSTFILES | ||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE DeleteSectionsINI | |||
!insertmacro MUI_PAGE_FINISH | !insertmacro MUI_PAGE_FINISH | ||
Line 47: | Line 43: | ||
##=========================================================================== | ##=========================================================================== | ||
## | ## Language strings | ||
##=========================================================================== | ##=========================================================================== | ||
! | LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!" | ||
LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Setup will install \ | |||
Program #1 in the following folder..." | |||
LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Setup will install \ | |||
Program #2 in the following folder..." | |||
##=========================================================================== | ##=========================================================================== | ||
## Start sections | ## Start sections | ||
##=========================================================================== | ##=========================================================================== | ||
## Sections Group 1 | ## Sections Group 1 | ||
SectionGroup "Program #1" PROG1 | SectionGroup /e "Program #1" PROG1 | ||
Section "Main" SEC1 | Section "Main" SEC1 | ||
##All the files in Group 1 will be installed to the same location, $INSTDIR | |||
SetOutPath "$INSTDIR" | |||
## Main files to install here | ## Main files to install here | ||
messagebox mb_ok sec1 | messagebox mb_ok sec1 | ||
SectionEnd | SectionEnd | ||
Section "Other" SEC2 | Section "Other" SEC2 | ||
## Other files to install here | ## Other files to install here | ||
messagebox mb_ok sec2 | messagebox mb_ok sec2 | ||
SectionEnd | SectionEnd | ||
SectionGroupEnd | SectionGroupEnd | ||
Section "-FixSilent" | |||
Call FixSilentProg2 | |||
SectionEnd | |||
## Sections Group 2 | ## Sections Group 2 | ||
SectionGroup "Program #2" PROG2 | SectionGroup /e "Program #2" PROG2 | ||
Section "Main" SEC3 | Section "Main" SEC3 | ||
##All the files in Group 2 will be installed to the same location, $INSTDIR | |||
SetOutPath "$INSTDIR" | |||
## Main files to install here | ## Main files to install here | ||
messagebox mb_ok sec3 | messagebox mb_ok sec3 | ||
SectionEnd | SectionEnd | ||
Section "Other" SEC4 | Section "Other" SEC4 | ||
## Other files to install here | ## Other files to install here | ||
messagebox mb_ok sec4 | messagebox mb_ok sec4 | ||
SectionEnd | SectionEnd | ||
SectionGroupEnd | |||
## | ##=========================================================================== | ||
## Settings | |||
##=========================================================================== | |||
!define PROG1_InstDir "C:\PROG1" | |||
!define PROG1_StartIndex ${PROG1} | |||
!define PROG1_EndIndex ${SEC2} | |||
!define PROG2_InstDir "C:\PROG2" | |||
!define PROG2_StartIndex ${PROG2} | |||
!define PROG2_EndIndex ${SEC4} | |||
##=========================================================================== | ##=========================================================================== | ||
## Please don't modify below here unless you're a NSIS 'wiz-kid' | ## Please don't modify below here unless you're a NSIS 'wiz-kid' | ||
##=========================================================================== | ##=========================================================================== | ||
## Create $PLUGINSDIR | ## Create $PLUGINSDIR | ||
Function .onInit | Function .onInit | ||
InitPluginsDir | InitPluginsDir | ||
${If} ${Silent} | |||
StrCpy $InstDir ${PROG1_InstDir} | |||
${EndIf} | |||
FunctionEnd | FunctionEnd | ||
Function FixSilentProg2 | |||
${If} ${Silent} | |||
StrCpy $InstDir ${PROG2_InstDir} | |||
${EndIf} | |||
FunctionEnd | |||
## If user goes back to this page from 1st Directory page | ## If user goes back to this page from 1st Directory page | ||
## we need to put the sections back to how they were before | ## we need to put the sections back to how they were before | ||
Var IfBack | Var IfBack | ||
Function SelectFilesCheck | |||
Function | |||
StrCmp $IfBack 1 0 NoCheck | StrCmp $IfBack 1 0 NoCheck | ||
Call | Call ResetFiles | ||
NoCheck: | NoCheck: | ||
FunctionEnd | |||
## Also if no sections are selected, warn the user! | |||
Function ComponentsLeave | |||
Push $R0 | |||
Push $R1 | |||
Call IsPROG1Selected | |||
Pop $R0 | |||
Call IsPROG2Selected | |||
Pop $R1 | |||
StrCmp $R0 1 End | |||
StrCmp $R1 1 End | |||
Pop $R1 | |||
Pop $R0 | |||
MessageBox MB_OK|MB_ICONEXCLAMATION "$(NoSectionsSelected)" | |||
Abort | |||
End: | |||
Pop $R1 | |||
Pop $R0 | |||
FunctionEnd | FunctionEnd | ||
Function IsPROG1Selected | |||
Function | |||
Push $R0 | Push $R0 | ||
Push $R1 | |||
Pop $R0 | StrCpy $R0 ${PROG1_StartIndex} # Group 1 start | ||
Loop: | |||
IntOp $R0 $R0 + 1 | |||
SectionGetFlags $R0 $R1 # Get section flags | |||
IntOp $R1 $R1 & ${SF_SELECTED} | |||
StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done | |||
StrCpy $R0 1 | |||
Goto Done | |||
StrCmp $R0 ${PROG1_EndIndex} 0 Loop | |||
Done: | |||
Pop $R1 | |||
Exch $R0 | |||
FunctionEnd | FunctionEnd | ||
Function IsPROG2Selected | |||
Push $R0 | |||
Push $R1 | |||
StrCpy $R0 ${PROG2_StartIndex} # Group 2 start | |||
Loop: | |||
IntOp $R0 $R0 + 1 | |||
SectionGetFlags $R0 $R1 # Get section flags | |||
IntOp $R1 $R1 & ${SF_SELECTED} | |||
StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done | |||
StrCpy $R0 1 | |||
Goto Done | |||
StrCmp $R0 ${PROG2_EndIndex} 0 Loop | |||
Done: | |||
Pop $R1 | |||
Exch $R0 | |||
FunctionEnd | |||
## Here we are selecting first sections to install | ## Here we are selecting first sections to install | ||
## by unselecting all the others! | ## by unselecting all the others! | ||
Function SelectFilesA | Function SelectFilesA | ||
# If user clicks Back now, we will know to reselect Group 2's sections for | # If user clicks Back now, we will know to reselect Group 2's sections for | ||
# Components page | # Components page | ||
StrCpy $IfBack 1 | StrCpy $IfBack 1 | ||
# We need to save the state of the Group 2 Sections | # We need to save the state of the Group 2 Sections | ||
# for the next InstFiles page | # for the next InstFiles page | ||
Push $R0 | |||
Push $R1 | |||
StrCpy $R0 ${ | StrCpy $R0 ${PROG2_StartIndex} # Group 2 start | ||
Loop: | Loop: | ||
IntOp $R0 $R0 + 1 | IntOp $R0 $R0 + 1 | ||
Line 149: | Line 222: | ||
WriteINIStr "$PLUGINSDIR\sections.ini" Sections $R0 $R1 # Save state | WriteINIStr "$PLUGINSDIR\sections.ini" Sections $R0 $R1 # Save state | ||
!insertmacro UnselectSection $R0 # Then unselect it | !insertmacro UnselectSection $R0 # Then unselect it | ||
StrCmp $R0 ${ | StrCmp $R0 ${PROG2_EndIndex} 0 Loop | ||
# Don't install prog 1? | |||
Call IsPROG1Selected | |||
Pop $R0 | |||
StrCmp $R0 1 +4 | |||
Pop $R1 | |||
Pop $R0 | |||
Abort | |||
# Set current $INSTDIR to PROG1_InstDir define | # Set current $INSTDIR to PROG1_InstDir define | ||
StrCpy $INSTDIR "${PROG1_InstDir}" | StrCpy $INSTDIR "${PROG1_InstDir}" | ||
Pop $R1 | |||
Pop $R0 | |||
FunctionEnd | FunctionEnd | ||
## Here we need to unselect all Group 1 sections | ## Here we need to unselect all Group 1 sections | ||
## and then re-select those in Group 2 (that the user had selected on | ## and then re-select those in Group 2 (that the user had selected on | ||
## Components page) | ## Components page) | ||
Function SelectFilesB | Function SelectFilesB | ||
Push $R0 | |||
Push $R1 | |||
StrCpy $R0 ${PROG1_StartIndex} # Group 1 start | |||
Loop: | |||
IntOp $R0 $R0 + 1 | |||
!insertmacro UnselectSection $R0 # Unselect it | |||
StrCmp $R0 ${PROG1_EndIndex} 0 Loop | |||
Call ResetFiles | |||
Call | |||
# Don't install prog 2? | # Don't install prog 2? | ||
StrCmp $ | Call IsPROG2Selected | ||
Pop $R0 | |||
StrCmp $R0 1 +4 | |||
Pop $R1 | |||
Pop $R0 | |||
Abort | Abort | ||
# Set current $INSTDIR to PROG2_InstDir define | # Set current $INSTDIR to PROG2_InstDir define | ||
StrCpy $INSTDIR "${PROG2_InstDir}" | StrCpy $INSTDIR "${PROG2_InstDir}" | ||
Pop $R1 | |||
Pop $R0 | |||
FunctionEnd | FunctionEnd | ||
## This will set all sections to how they were on the components page | ## This will set all sections to how they were on the components page | ||
## originally | ## originally | ||
Function | Function ResetFiles | ||
Push $R0 | |||
Push $R1 | |||
StrCpy $R0 ${PROG2_StartIndex} # Group 2 start | |||
StrCpy $R0 ${ | |||
Loop: | Loop: | ||
Line 204: | Line 282: | ||
ReadINIStr "$R1" "$PLUGINSDIR\sections.ini" Sections $R0 # Get sec flags | ReadINIStr "$R1" "$PLUGINSDIR\sections.ini" Sections $R0 # Get sec flags | ||
SectionSetFlags $R0 $R1 # Re-set flags for this sec | SectionSetFlags $R0 $R1 # Re-set flags for this sec | ||
StrCmp $R0 ${ | StrCmp $R0 ${PROG2_EndIndex} 0 Loop | ||
Pop $R1 | |||
Pop $R0 | |||
FunctionEnd | FunctionEnd | ||
## Here we are deleting the temp INI file at the end of installation | ## Here we are deleting the temp INI file at the end of installation | ||
Function DeleteSectionsINI | Function DeleteSectionsINI | ||
FlushINI "$PLUGINSDIR\Sections.ini" | |||
Delete "$PLUGINSDIR\Sections.ini" | Delete "$PLUGINSDIR\Sections.ini" | ||
FunctionEnd | FunctionEnd | ||
</highlight-nsis> | </highlight-nsis> | ||
Line 231: | Line 299: | ||
-Stu | -Stu | ||
[[ | [[Category:Code Examples]] |
Latest revision as of 13:45, 15 February 2021
Author: Afrow UK (talk, contrib) |
Description
This script shows how we can install two programs with one installer, where each program has its own Directory and InstFiles page. Obviously we still have the single Components page though, as if we chose to have two then we'd might as well make two installer exe's!
The Script
Here's the code. You can compile this script straight off. I've added MessageBox's to test it.
Name "Multiple InstFiles" OutFile "multi-install.exe" !include MUI.nsh !include Sections.nsh ##=========================================================================== ## Modern UI Pages ##=========================================================================== !insertmacro MUI_PAGE_WELCOME !define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesCheck !define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave !insertmacro MUI_PAGE_COMPONENTS ## This is the title on the first Directory page !define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_A)" !define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesA !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES ## This is the title on the second Directory page !define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_B)" !define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesB !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !define MUI_PAGE_CUSTOMFUNCTION_LEAVE DeleteSectionsINI !insertmacro MUI_PAGE_FINISH !insertmacro MUI_LANGUAGE "English" ##=========================================================================== ## Language strings ##=========================================================================== LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!" LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Setup will install \ Program #1 in the following folder..." LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Setup will install \ Program #2 in the following folder..." ##=========================================================================== ## Start sections ##=========================================================================== ## Sections Group 1 SectionGroup /e "Program #1" PROG1 Section "Main" SEC1 ##All the files in Group 1 will be installed to the same location, $INSTDIR SetOutPath "$INSTDIR" ## Main files to install here messagebox mb_ok sec1 SectionEnd Section "Other" SEC2 ## Other files to install here messagebox mb_ok sec2 SectionEnd SectionGroupEnd Section "-FixSilent" Call FixSilentProg2 SectionEnd ## Sections Group 2 SectionGroup /e "Program #2" PROG2 Section "Main" SEC3 ##All the files in Group 2 will be installed to the same location, $INSTDIR SetOutPath "$INSTDIR" ## Main files to install here messagebox mb_ok sec3 SectionEnd Section "Other" SEC4 ## Other files to install here messagebox mb_ok sec4 SectionEnd SectionGroupEnd ##=========================================================================== ## Settings ##=========================================================================== !define PROG1_InstDir "C:\PROG1" !define PROG1_StartIndex ${PROG1} !define PROG1_EndIndex ${SEC2} !define PROG2_InstDir "C:\PROG2" !define PROG2_StartIndex ${PROG2} !define PROG2_EndIndex ${SEC4} ##=========================================================================== ## Please don't modify below here unless you're a NSIS 'wiz-kid' ##=========================================================================== ## Create $PLUGINSDIR Function .onInit InitPluginsDir ${If} ${Silent} StrCpy $InstDir ${PROG1_InstDir} ${EndIf} FunctionEnd Function FixSilentProg2 ${If} ${Silent} StrCpy $InstDir ${PROG2_InstDir} ${EndIf} FunctionEnd ## If user goes back to this page from 1st Directory page ## we need to put the sections back to how they were before Var IfBack Function SelectFilesCheck StrCmp $IfBack 1 0 NoCheck Call ResetFiles NoCheck: FunctionEnd ## Also if no sections are selected, warn the user! Function ComponentsLeave Push $R0 Push $R1 Call IsPROG1Selected Pop $R0 Call IsPROG2Selected Pop $R1 StrCmp $R0 1 End StrCmp $R1 1 End Pop $R1 Pop $R0 MessageBox MB_OK|MB_ICONEXCLAMATION "$(NoSectionsSelected)" Abort End: Pop $R1 Pop $R0 FunctionEnd Function IsPROG1Selected Push $R0 Push $R1 StrCpy $R0 ${PROG1_StartIndex} # Group 1 start Loop: IntOp $R0 $R0 + 1 SectionGetFlags $R0 $R1 # Get section flags IntOp $R1 $R1 & ${SF_SELECTED} StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done StrCpy $R0 1 Goto Done StrCmp $R0 ${PROG1_EndIndex} 0 Loop Done: Pop $R1 Exch $R0 FunctionEnd Function IsPROG2Selected Push $R0 Push $R1 StrCpy $R0 ${PROG2_StartIndex} # Group 2 start Loop: IntOp $R0 $R0 + 1 SectionGetFlags $R0 $R1 # Get section flags IntOp $R1 $R1 & ${SF_SELECTED} StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done StrCpy $R0 1 Goto Done StrCmp $R0 ${PROG2_EndIndex} 0 Loop Done: Pop $R1 Exch $R0 FunctionEnd ## Here we are selecting first sections to install ## by unselecting all the others! Function SelectFilesA # If user clicks Back now, we will know to reselect Group 2's sections for # Components page StrCpy $IfBack 1 # We need to save the state of the Group 2 Sections # for the next InstFiles page Push $R0 Push $R1 StrCpy $R0 ${PROG2_StartIndex} # Group 2 start Loop: IntOp $R0 $R0 + 1 SectionGetFlags $R0 $R1 # Get section flags WriteINIStr "$PLUGINSDIR\sections.ini" Sections $R0 $R1 # Save state !insertmacro UnselectSection $R0 # Then unselect it StrCmp $R0 ${PROG2_EndIndex} 0 Loop # Don't install prog 1? Call IsPROG1Selected Pop $R0 StrCmp $R0 1 +4 Pop $R1 Pop $R0 Abort # Set current $INSTDIR to PROG1_InstDir define StrCpy $INSTDIR "${PROG1_InstDir}" Pop $R1 Pop $R0 FunctionEnd ## Here we need to unselect all Group 1 sections ## and then re-select those in Group 2 (that the user had selected on ## Components page) Function SelectFilesB Push $R0 Push $R1 StrCpy $R0 ${PROG1_StartIndex} # Group 1 start Loop: IntOp $R0 $R0 + 1 !insertmacro UnselectSection $R0 # Unselect it StrCmp $R0 ${PROG1_EndIndex} 0 Loop Call ResetFiles # Don't install prog 2? Call IsPROG2Selected Pop $R0 StrCmp $R0 1 +4 Pop $R1 Pop $R0 Abort # Set current $INSTDIR to PROG2_InstDir define StrCpy $INSTDIR "${PROG2_InstDir}" Pop $R1 Pop $R0 FunctionEnd ## This will set all sections to how they were on the components page ## originally Function ResetFiles Push $R0 Push $R1 StrCpy $R0 ${PROG2_StartIndex} # Group 2 start Loop: IntOp $R0 $R0 + 1 ReadINIStr "$R1" "$PLUGINSDIR\sections.ini" Sections $R0 # Get sec flags SectionSetFlags $R0 $R1 # Re-set flags for this sec StrCmp $R0 ${PROG2_EndIndex} 0 Loop Pop $R1 Pop $R0 FunctionEnd ## Here we are deleting the temp INI file at the end of installation Function DeleteSectionsINI FlushINI "$PLUGINSDIR\Sections.ini" Delete "$PLUGINSDIR\Sections.ini" FunctionEnd
If you need some help, feel free to PM me (Afrow UK) via the NSIS forums.
-Stu