Two installations in one installer: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
m (Adding new author and category links.)
(Fix silent installers)
 
(11 intermediate revisions by 8 users not shown)
Line 2: Line 2:


== 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 bloody installer exe's!
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. You should put some files in the Sections first though, otherwise you can't really see it 'working'...
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 19: Line 19:
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_WELCOME


!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesBCheck
!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 "Setup will install Program #1 in the \
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_A)"
following folder..."
 
!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 "Setup will install Program #2 in the \
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_B)"
following folder..."


!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesB
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesB
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_DIRECTORY
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE DeleteSectionsINI
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_INSTFILES


!define MUI_PAGE_CUSTOMFUNCTION_LEAVE DeleteSectionsINI
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_PAGE_FINISH


Line 45: Line 43:


##===========================================================================
##===========================================================================
## Install dir's
## Language strings
##===========================================================================
##===========================================================================


!define PROG1_InstDir "C:\PROG1"
LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!"
!define PROG2_InstDir "C:\PROG2"
 
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
  SectionIn RO
  ##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


## This must be the last section
##===========================================================================
Section -dummy SEC_LAST
## Settings
SectionEnd
##===========================================================================


SectionGroupEnd
!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
Var UseProg2
Function SelectFilesCheck
Function SelectFilesBCheck
  StrCmp $IfBack 1 0 NoCheck
  StrCmp $IfBack 1 0 NoCheck
   Call ResetFilesB
   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


## Check if PROG2 needs to be installed!
Function IsPROG1Selected
Function ComponentsLeave
Push $R0
Push $R0
  SectionGetFlags ${PROG2} $R0
Push $R1
IntOp $UseProg2 $R0 & ${SF_SELECTED}
 
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 $R0
Push $R1
Push $R1
 
  StrCpy $R0 ${PROG2} # Group 2 start
  StrCpy $R0 ${PROG2_StartIndex} # Group 2 start
 
   Loop:
   Loop:
   IntOp $R0 $R0 + 1
   IntOp $R0 $R0 + 1
Line 147: 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 ${Sec_LAST} 0 Loop
     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 $R1
Pop $R0
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


Push $R0
  Loop:
Push $R1
  IntOp $R0 $R0 + 1
 
    !insertmacro UnselectSection $R0 # Unselect it
StrCpy $R0 1       # Group 1 start
    StrCmp $R0 ${PROG1_EndIndex} 0 Loop
StrCpy $R1 ${PROG2} # Group 1 finish
 
  Call ResetFiles
  Loop1:
  !insertmacro UnselectSection $R0   # Unselect section
  StrCmp $R0 $R1 Done1
    IntOp $R0 $R0 + 1
    Goto Loop1   # Go to next section(s)
  Done1:
 
  Call ResetFilesB
 
  # Don't install prog 2?
  # Don't install prog 2?
  StrCmp $UseProg2 1 +2
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 $R1
Pop $R0
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 ResetFilesB
Function ResetFiles
 
Push $R0
Push $R0
Push $R1
Push $R1
 
  StrCpy $R0 ${PROG2_StartIndex}    # Group 2 start
  StrCpy $R0 ${PROG2}    # Group 2 starts at SEC3!


   Loop:
   Loop:
Line 202: 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 ${Sec_LAST} 0 Loop
     StrCmp $R0 ${PROG2_EndIndex} 0 Loop
 
Pop $R1
Pop $R1
Pop $R0
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"
FlushINI "$PLUGINSDIR\Sections.ini"
FunctionEnd
Function .onSelChange
Push $R0
SectionGetFlags ${SEC4} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
StrCmp $R0 ${SF_SELECTED} 0 NoSelectMain
  !insertmacro SelectSection ${SEC3}
NoSelectMain:
Pop $R0
FunctionEnd
FunctionEnd
</highlight-nsis>
</highlight-nsis>

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