NSIS - Custom Page, problems with a droplist - nsis

I have this Custom Page in my code, where there is a droplist with the available drives on the computer. When the user chooses the drive he wants, a .txt file is created where is written that drive (example: E:).
When you open the custom page, the drive that appear on the droplist is "C:\". But if I hit "next" without clicking on the droplist, the .txt file is not created. Even if I want C:\ and it's already there, I have to go there and click to make it work. If I don't click on the droplist before hiting "next", nothing happen.
Anybody knows why? The code is down below:
!include "MUI2.nsh"
!include FileFunc.nsh
!insertmacro GetDrives
var newCheckBox
!define NOME "S-Monitor"
Name "${NOME}"
OutFile "${NOME}.exe"
InstallDir "C:\${NOME}"
ShowInstDetails show
AllowRootDirInstall true
;--- Paginas ---
!define MUI_ICON Labels\SetupICO.ico
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP Labels\Header.bmp
!define MUI_WELCOMEFINISHPAGE_BITMAP Labels\Left.bmp
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
Page Custom CustomCreate CustomLeave
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_CHECKED
!define MUI_FINISHPAGE_RUN_TEXT "Criar atalho na Área de Trabalho"
!define MUI_FINISHPAGE_RUN_FUNCTION "AtalhoDesktop"
!define MUI_PAGE_CUSTOMFUNCTION_SHOW showNewCheckbox
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE launchNewLink
!insertmacro MUI_PAGE_FINISH
;--- Idiomas ---
!insertmacro MUI_LANGUAGE "Portuguese"
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "Spanish"
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
InitPluginsDir
GetTempFileName $0
Rename $0 '$PLUGINSDIR\custom.ini'
FunctionEnd
;--------------------------------
;Arquivos a serem instalados
Section "Instalacao"
SetShellVarContext all
SetOutPath "$INSTDIR"
File /r Ficheiros\*.* ; LOCALIZACAO DA APLICACAO DO S-MONITOR
MessageBox MB_OK "O software BDE (Borland Database Engine) será instalado agora"
ExecWait "$INSTDIR\bde_install_Win7_32_e_64.exe"
FileOpen $1 '$INSTDIR\S-monitor.cpy' w
FileWrite $1 "CPY Location=C:\S-Monitor.cpy"
FileClose $1
writeUninstaller $INSTDIR\uninstall.exe
SectionEnd
Section "Uninstall"
MessageBox MB_YESNO "Deseja desinstalar o S-Monitor?" IDYES true IDNO false
true:
SetShellVarContext all
delete $INSTDIR\uninstall.exe
RMDir /R /REBOOTOK $INSTDIR
Goto +2
false:
MessageBox MB_OK "Desinstalação cancelada."
SectionEnd
Function AtalhoDesktop
createShortCut "$DESKTOP\S-Monitor.lnk" "C:\SMonitor.exe"
FunctionEnd
Function showNewCheckbox
${NSD_CreateCheckbox} 120u 110u 100% 10u "&Iniciar o S-Monitor ao terminar a instalação"
Pop $newCheckBox
FunctionEnd
Function launchNewLink
${NSD_GetState} $newCheckBox $0
${If} $0 <> 0
Exec "C:\S-Monitor\Smonitor.exe"
${EndIf}
FunctionEnd
Function CustomCreate
WriteIniStr '$PLUGINSDIR\custom.ini' 'Settings' 'NumFields' '6'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Type' 'Label'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Left' '5'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Top' '5'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Right' '-6'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Bottom' '60'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Text' \
'Escolha a que disco rígido quer associar a sua licença do S-Monitor.\nA instalação do S-Monitor ficará associada de forma permanente ao disco escolhido.\n\nSe desejar transferir a sua licença para outro PC mais tarde, deverá escolher um disco amovível neste passo.\nSe não sabe que opção escolher, deixe seleccionada a opção por defeito.'
StrCpy $R2 0
StrCpy $R0 ''
${GetDrives} "HDD+FDD" GetDrivesCallBack
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Type' 'DropList'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Left' '30'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Top' '64'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Right' '-31'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Bottom' '200'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Flags' 'Notify'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'State' '$R1'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'ListItems' '$R0'
push $0
InstallOptions::Dialog '$PLUGINSDIR\custom.ini'
pop $0
pop $0
FunctionEnd
Function CustomLeave
ReadIniStr $0 '$PLUGINSDIR\custom.ini' 'Settings' 'State'
StrCmp $0 '2' 0 next
ReadIniStr $0 '$PLUGINSDIR\custom.ini' 'Field 2' 'State'
strcpy $R0 $0
StrCpy $0 $0 3
FileOpen $1 '$INSTDIR\S-monitor.cpy' w
FileWrite $1 "CPY Location=$R0S-Monitor.cpy"
FileClose $1
Abort
next:
ReadIniStr $0 '$PLUGINSDIR\custom.ini' 'Field 2' 'State'
StrCpy '$INSTDIR' '$0'
FunctionEnd
Function GetDrivesCallBack
StrCmp $R2 '0' 0 next
StrCpy $R3 '$R4'
StrCpy $R1 '$9'
IntOp $R2 $R2 + 1
next:
StrCpy $R0 '$R0$9|'
Push $0
FunctionEnd

Related

Files for both applications are installed in both destination folders

Please note that I initially created an installer for two applications based on https://nsis.sourceforge.io/Two_installations_in_one_installer where the first application is the main one while the second application is the license manager. That said, I did remove the nested checkboxes with only one layer of checkboxes. FYI, I have also been referencing this article: https://www.codeproject.com/Articles/24187/Creating-an-Installer?msg=5782957#xx5782957xx
The issue that I am having is that when I run the installer, all of the files from MyApp and FlexLM are installed in the $PROGRAMFILES64\${PRODUCT_NAME} folder and in the C:\${FLEX_DIR}. So when I am installing two applications, it looks like both SEC1 and SEC3 are executed for the MyApp installation and both SEC1 and SEC3 are executed for the FlexLM installation:
!include "LogicLib.nsh"
!include "Sections.nsh"
;Include Modern UI
!include "MUI2.nsh"
!define MAJOR_VERSION "1"
!define MINOR_VERSION "2"
!define PATCH_VERSION "3"
!define BUILD_VERSION "4"
!define APP_COPYRIGHT "MyApp © MyCompany 2021"
!define COMPANY_NAME "MyCompany"
!define FLEX_LM "FlexLM"
!define FLEX_DIR "FlexSQI"
!define LANG_ENGLSH "English"
!define PRODUCT_NAME "MyApp"
!define PRODUCT_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}.${BUILD_VERSION}"
!define SETUP_NAME "MyAppSetup.exe"
BrandingText "MyCompany"
OutFile ${SETUP_NAME}
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}"
InstallDirRegKey HKLM "Software\$PRODUCT_NAME" ""
ShowInstDetails hide
ShowUnInstDetails hide
SetCompressor /SOLID lzma
SetCompressorDictSize 12
Var MyAppCheckboxState
Var FlexLmCheckboxState
;Request application privileges for Windows
RequestExecutionLevel admin
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "MyAppLicense.txt"
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesCheck
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave
!insertmacro MUI_PAGE_COMPONENTS
## This is the title on the MyApp 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 FlexLM 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_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!"
LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Setup will install \
${PRODUCT_NAME} in the following folder..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Setup will install \
${FLEX_LM} in the following folder..."
;--------------------------------
; Settings
!define PROG1_InstDir "$PROGRAMFILES64\${PRODUCT_NAME}"
!define PROG1_StartIndex ${SEC1}
!define PROG1_EndIndex ${SEC1}
!define PROG2_InstDir "C:\${FLEX_DIR}"
!define PROG2_StartIndex ${SEC3}
!define PROG2_EndIndex ${SEC3}
;--------------------------------
; Start sections
Section "MyApp" SEC1
StrCpy $MyAppCheckboxState ${BST_CHECKED}
${If} $MyAppCheckboxState == ${BST_CHECKED}
##All the files in Group 1 will be installed to the same location, $INSTDIR
SetOutPath "$INSTDIR"
# specify files to go in output path
File config.dat
File MyApp.exe
File ReleaseNotes.txt
File MyCompany_LandingPage_114.bmp
File MyAppLicense.txt
# create a shortcut named "new shortcut" in the start menu programs directory
CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$PROGRAMFILES64\${PRODUCT_NAME}\${PRODUCT_NAME}.exe"
# Add application to registry
ClearErrors
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'Company Name' "${COMPANY_NAME}"
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'Version' "${PRODUCT_VERSION}"
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'AppID' "{0be21143-9089-47fa-9736-c45609d13d70}"
# Add program to Add/Remove programs
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayIcon" "$PROGRAMFILES64\${PRODUCT_NAME}\${PRODUCT_NAME}.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"AppID" "{0be21143-9089-47fa-9736-c45609d13d70}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"Publisher" "${COMPANY_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"UninstallString" "$\"$INSTDIR\uninstaller.exe$\""
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
${EndIf}
# messagebox mb_ok sec1
SectionEnd
Section "FlexLM" SEC3
StrCpy $FlexLmCheckboxState ${BST_CHECKED}
${If} $FlexLmCheckboxState == ${BST_CHECKED}
##All the files in Group 2 will be installed to the same location, $INSTDIR
SetOutPath "$INSTDIR"
File installs.exe
File lmdown.exe
File lmflex.exe
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
${EndIf}
# messagebox mb_ok sec3
SectionEnd
;--------------------------------
;Descriptions
;Language strings
LangString DESC_SecMyApp ${LANG_ENGLISH} "MyAppTM software is an easy-to-use suite of tools."
LangString DESC_SecFlexLM ${LANG_ENGLISH} "FlexSQI contains all the files necessary to implement the FlexLM license server."
;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC1} $(DESC_SecMyApp)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC3} $(DESC_SecFlexLM)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section "Uninstall"
# Always delete uninstaller first
Delete $INSTDIR\uninstaller.exe
# now delete installed files and registry keys for MyApp
Delete $INSTDIR\config.dat
Delete $INSTDIR\MyApp.exe
Delete $INSTDIR\ReleaseNotes.txt
Delete $INSTDIR\MyCompany_LandingPage_114.bmp
Delete $INSTDIR\MyAppLicense.txt
Delete "$SMPROGRAMS\MyApp.lnk"
DeleteRegKey HKCU "SOFTWARE\${PRODUCT_NAME}"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
DeleteRegKey /ifempty HKCU "Software\Modern UI Test"
# now delete installed files and registry keys for FlexLM
Delete $INSTDIR\lmdown.exe
Delete $INSTDIR\lmflex.exe
Delete $INSTDIR\installs.exe
# Delete the MyApp and FlexLM directories
RMDir $INSTDIR
SectionEnd
;--------------------------------
; Please don`t modify below here unless you`re a NSIS 'wiz-kid'
## Create $PLUGINSDIR
Function .onInit
InitPluginsDir
SetOutPath $TEMP
File /oname=spltmp.bmp "MyCompany_LandingPage_114.bmp"
splash::show 2000 $TEMP\spltmp
Pop $0 ; $0 has '1' if the user closed the splash screen early,
; '0' if everything closed normally, and '-1' if some error occurred.
Delete $TEMP\spltmp.bmp
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
StrCpy $R0 ${PROG1_StartIndex} # Group 1 start
SectionGetFlags 0 $R0 # Get section flags
IntOp $R0 $R0 & ${SF_SELECTED}
StrCmp $R0 ${SF_SELECTED} 0 +3 # If section is selected, done
StrCpy $R0 1
Exch $R0
FunctionEnd
Function IsPROG2Selected
Push $R1
StrCpy $R1 ${PROG2_StartIndex} # Group 2 start
IntOp $R1 $R1 + 1
SectionGetFlags 1 $R1 # Get section flags
IntOp $R1 $R1 & ${SF_SELECTED}
StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done
StrCpy $R1 1
Exch $R1
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
## Here we are deleting the temp INI file at the end of installation
Function DeleteSectionsINI
FlushINI "$PLUGINSDIR\Sections.ini"
Delete "$PLUGINSDIR\Sections.ini"
FunctionEnd
How can I get only the MyApp files to be installed in $PROGRAMFILES64${PRODUCT_NAME} (i.e., the files from SEC1), and only the Files from FlexLM to be installed in C:\FlexLM? TIA.
UPDATE:
Please find my updated code here:
!include "LogicLib.nsh"
!include "Sections.nsh"
;Include Modern UI
!include "MUI2.nsh"
!define MAJOR_VERSION "1"
!define MINOR_VERSION "2"
!define PATCH_VERSION "3"
!define BUILD_VERSION "4"
!define APP_COPYRIGHT "MyApp © MyCompany 2021"
!define COMPANY_NAME "MyCompany"
!define FLEX_LM "FlexLM"
!define FLEX_DIR "FlexSQI"
!define LANG_ENGLSH "English"
!define PRODUCT_NAME "MyApp"
!define PRODUCT_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}.${BUILD_VERSION}"
!define SETUP_NAME "MyAppSetup.exe"
BrandingText "MyCompany"
OutFile ${SETUP_NAME}
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}\"
InstallDirRegKey HKLM "Software\$PRODUCT_NAME" ""
ShowInstDetails hide
ShowUnInstDetails hide
SetCompressor /SOLID lzma
SetCompressorDictSize 12
Var MyAppCheckboxState
Var FlexLmCheckboxState
Var MyAppInstallDir
Var FlexLmInstallDir
;Request application privileges for Windows
RequestExecutionLevel admin
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "MyAppLicense.txt"
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesCheck
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave
!insertmacro MUI_PAGE_COMPONENTS
## This is the title on the MyApp 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 FlexLM 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_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!"
LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Setup will install \
${PRODUCT_NAME} in the following folder..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Setup will install \
${FLEX_LM} in the following folder..."
;--------------------------------
; Settings
!define PROG1_InstDir "$PROGRAMFILES64\${PRODUCT_NAME}\"
!define PROG1_StartIndex ${SEC1}
!define PROG1_EndIndex ${SEC1}
!define PROG2_InstDir "C:\${FLEX_DIR}"
!define PROG2_StartIndex ${SEC3}
!define PROG2_EndIndex ${SEC3}
;--------------------------------
; Function
; StrContains
; This function does a case sensitive searches for an occurrence of a substring in a string.
; It returns the substring if it is found.
; Otherwise it returns null("").
; Written by kenglish_hi
; Adapted from StrReplace written by dandaman32
Var STR_HAYSTACK
Var STR_NEEDLE
Var STR_CONTAINS_VAR_1
Var STR_CONTAINS_VAR_2
Var STR_CONTAINS_VAR_3
Var STR_CONTAINS_VAR_4
Var STR_RETURN_VAR
Function StrContains
Exch $STR_NEEDLE
Exch 1
Exch $STR_HAYSTACK
; Uncomment to debug
;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK '
StrCpy $STR_RETURN_VAR ""
StrCpy $STR_CONTAINS_VAR_1 -1
StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE
StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK
loop:
IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1
StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1
StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found
StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done
Goto loop
found:
StrCpy $STR_RETURN_VAR $STR_NEEDLE
Goto done
done:
Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the
Exch $STR_RETURN_VAR
FunctionEnd
!macro _StrContainsConstructor OUT NEEDLE HAYSTACK
Push `${HAYSTACK}`
Push `${NEEDLE}`
Call StrContains
Pop `${OUT}`
!macroend
!define StrContains '!insertmacro "_StrContainsConstructor"'
;--------------------------------
; Start sections
Section "MyApp" SEC1
${If} ${SectionIsSelected} ${SEC1}
##All the files in Group 1 will be installed to the same location, $INSTDIR
SetOutPath "$INSTDIR"
;MessageBox MB_OK "SEC1 #1 INSTDIR is $INSTDIR"
${StrContains} $0 "MyQpp" "$INSTDIR"
;MessageBox MB_OK "SEC1 #2 0 is $0"
StrCmp $0 "" notfoundMyApp
StrCpy $MyAppInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #3 MyAppInstallDir is $MyAppInstallDir"
Goto doneMyApp
notfoundMyApp:
;MessageBox MB_OK 'Did not find MyApp string'
doneMyApp:
${StrContains} $0 "Flex" "$INSTDIR"
StrCmp $0 "" notfoundFlex
StrCpy $FlexLmInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #4 FlexLmInstallDir is $FlexLmInstallDir"
Goto doneFlex
notfoundFlex:
;MessageBox MB_OK 'Did not find Flex string'
# specify files to go in output path
File config.dat
File MyApp.exe
File ReleaseNotes.txt
File MyCompany_LandingPage_114.bmp
File MyAppLicense.txt
# create a shortcut named "new shortcut" in the start menu programs directory
CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$InstDir\${PRODUCT_NAME}.exe"
# Add application to registry
ClearErrors
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'Company Name' "${COMPANY_NAME}"
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'Version' "${PRODUCT_VERSION}"
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'AppID' "{A0E84732-E2B2-46E5-8CA2-462B8DF92DCD}"
# Add program to Add/Remove programs
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayIcon" "$PROGRAMFILES64\${PRODUCT_NAME}\${PRODUCT_NAME}.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"AppID" "{A0E84732-E2B2-46E5-8CA2-462B8DF92DCD}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"Publisher" "${COMPANY_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"UninstallString" "$\"$INSTDIR\uninstaller.exe$\""
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
doneFlex:
${EndIf}
# messagebox mb_ok sec1
SectionEnd
Section "FlexLM" SEC3
${If} ${SectionIsSelected} ${SEC3}
##All the files in Group 2 will be installed to the same location, $INSTDIR
SetOutPath "$INSTDIR"
;MessageBox MB_OK "SEC3 #1 INSTDIR is $INSTDIR"
;MessageBox MB_OK "SEC1 #1 INSTDIR is $INSTDIR"
${StrContains} $0 "Pro" "$INSTDIR"
;MessageBox MB_OK "SEC1 #2 0 is $0"
StrCmp $0 "" notfoundMyApp
StrCpy $MyAppInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #3 MyAppInstallDir is $MyAppInstallDir"
Goto doneMyApp
notfoundMyApp:
;MessageBox MB_OK 'Did not find MyApp string'
${StrContains} $0 "Flex" "$INSTDIR"
StrCmp $0 "" notfoundFlex
StrCpy $FlexLmInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #4 FlexLmInstallDir is $FlexLmInstallDir"
Goto doneFlex
notfoundFlex:
;MessageBox MB_OK 'Did not find Flex string'
doneFlex:
File installs.exe
File lmdown.exe
File lmflex.exe
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
doneQI:
${EndIf}
# messagebox mb_ok sec3
SectionEnd
;--------------------------------
;Descriptions
;Language strings
LangString DESC_SecMyApp ${LANG_ENGLISH} "MyAppTM software is an easy-to-use suite of tools."
LangString DESC_SecFlexLM ${LANG_ENGLISH} "FlexSQI contains all the files necessary to implement the FlexLM license server."
;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC1} $(DESC_SecMyApp)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC3} $(DESC_SecFlexLM)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section "Uninstall"
# Always delete uninstaller first
Delete $INSTDIR\uninstaller.exe
# now delete installed files and registry keys for MyApp
Delete $INSTDIR\config.dat
Delete $INSTDIR\MyApp.exe
Delete $INSTDIR\ReleaseNotes.txt
Delete $INSTDIR\MyCompany_LandingPage_114.bmp
Delete $INSTDIR\MyAppLicense.txt
Delete "$SMPROGRAMS\MyApp.lnk"
DeleteRegKey HKCU "SOFTWARE\${PRODUCT_NAME}"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
DeleteRegKey /ifempty HKCU "Software\Modern UI Test"
# now delete installed files and registry keys for FlexLM
Delete $INSTDIR\installs.exe
Delete $INSTDIR\lmborrow.exe
Delete $INSTDIR\lmflex.exe
# Delete the MyApp and FlexLM directories
RMDir $INSTDIR
SectionEnd
;--------------------------------
; Please don`t modify below here unless you`re a NSIS 'wiz-kid'
## Create $PLUGINSDIR
Function .onInit
InitPluginsDir
SetOutPath $TEMP
File /oname=spltmp.bmp "MyCompany_LandingPage_114.bmp"
splash::show 2000 $TEMP\spltmp
Pop $0 ; $0 has '1' if the user closed the splash screen early,
; '0' if everything closed normally, and '-1' if some error occurred.
Delete $TEMP\spltmp.bmp
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
StrCpy $R0 ${PROG1_StartIndex} # Group 1 start
SectionGetFlags 0 $R0 # Get section flags
IntOp $R0 $R0 & ${SF_SELECTED}
StrCmp $R0 ${SF_SELECTED} 0 +3 # If section is selected, done
StrCpy $R0 1
Exch $R0
FunctionEnd
Function IsPROG2Selected
Push $R1
StrCpy $R1 ${PROG2_StartIndex} # Group 2 start
IntOp $R1 $R1 + 1
SectionGetFlags 1 $R1 # Get section flags
IntOp $R1 $R1 & ${SF_SELECTED}
StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done
StrCpy $R1 1
Exch $R1
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
## Here we are deleting the temp INI file at the end of installation
Function DeleteSectionsINI
FlushINI "$PLUGINSDIR\Sections.ini"
Delete "$PLUGINSDIR\Sections.ini"
# FlexLM libs
;MessageBox MB_OK "DeleteSectionsINI #1 MyAppInstallDir is $MyAppInstallDir"
Delete $MyAppInstallDir\installs.exe
Delete $MyAppInstallDir\lmborrow.exe
# QI Pro files
;MessageBox MB_OK "DeleteSectionsINI #1 FlexLmInstallDir is $FlexLmInstallDir"
Delete $FlexLmInstallDir\config.dat
Delete $FlexLmInstallDir\MyApp.exe
Delete $FlexLmInstallDir\ReleaseNotes.txt
Delete $FlexLmInstallDir\MyApp_LandingPage_114.bmp
Delete $FlexLmInstallDir\MyAppLicense.txt
FunctionEnd
I just tested the code from the Wiki and it works perfectly. You commented out the loop in SelectFilesA/B so no wonder the section logic is broken in your example.
You also have some other issues:
StrCpy $MyAppCheckboxState ${BST_CHECKED}
${If} $MyAppCheckboxState == ${BST_CHECKED}
This makes no sense, this will always be true!
Also, CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$PROGRAMFILES64\${PRODUCT_NAME}\${PRODUCT_NAME}.exe" is wrong, it should be CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$InstDir\${PRODUCT_NAME}.exe".
UPDATE 2:
Here is my final solution--many thanks to #Anders. It may not be the most ideal or elegant solution, but it works for what I need. I tried to add this to my question but for some reason SO won't let me.
!include "LogicLib.nsh"
!include "Sections.nsh"
;Include Modern UI
!include "MUI2.nsh"
!define MAJOR_VERSION "1"
!define MINOR_VERSION "2"
!define PATCH_VERSION "3"
!define BUILD_VERSION "4"
!define APP_COPYRIGHT "MyApp © MyCompany 2021"
!define COMPANY_NAME "MyCompany"
!define FLEX_LM "FlexLM"
!define FLEX_DIR "FlexSQI"
!define LANG_ENGLSH "English"
!define PRODUCT_NAME "MyApp"
!define PRODUCT_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}.${BUILD_VERSION}"
!define SETUP_NAME "MyAppSetup.exe"
BrandingText "MyCompany"
OutFile ${SETUP_NAME}
Name "${PRODUCT_NAME}"
InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}\"
InstallDirRegKey HKLM "Software\$PRODUCT_NAME" ""
ShowInstDetails hide
ShowUnInstDetails hide
SetCompressor /SOLID lzma
SetCompressorDictSize 12
Var MyAppInstallDir
Var FlexLmInstallDir
;Request application privileges for Windows
RequestExecutionLevel admin
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "MyAppLicense.txt"
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesCheck
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave
!insertmacro MUI_PAGE_COMPONENTS
## This is the title on the MyApp Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_A)"
!define MUI_PAGE_HEADER_SUBTEXT "Please choose the folder in which to install MyApp."
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesA
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
## This is the title on the FlexLM Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_B)"
!define MUI_PAGE_HEADER_SUBTEXT "Please choose the folder in which to install FlexLM."
!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_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!"
LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Setup will install \
${PRODUCT_NAME} in the following folder..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Setup will install \
${FLEX_LM} in the following folder..."
;--------------------------------
; Settings
!define PROG1_InstDir "$PROGRAMFILES64\${PRODUCT_NAME}\"
!define PROG1_StartIndex ${SEC1}
!define PROG1_EndIndex ${SEC1}
!define PROG2_InstDir "C:\${FLEX_DIR}"
!define PROG2_StartIndex ${SEC3}
!define PROG2_EndIndex ${SEC3}
;--------------------------------
; Function
; StrContains
; This function does a case sensitive searches for an occurrence of a substring in a string.
; It returns the substring if it is found.
; Otherwise it returns null("").
; Written by kenglish_hi
; Adapted from StrReplace written by dandaman32
Var STR_HAYSTACK
Var STR_NEEDLE
Var STR_CONTAINS_VAR_1
Var STR_CONTAINS_VAR_2
Var STR_CONTAINS_VAR_3
Var STR_CONTAINS_VAR_4
Var STR_RETURN_VAR
Function StrContains
Exch $STR_NEEDLE
Exch 1
Exch $STR_HAYSTACK
; Uncomment to debug
;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK '
StrCpy $STR_RETURN_VAR ""
StrCpy $STR_CONTAINS_VAR_1 -1
StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE
StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK
loop:
IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1
StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1
StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found
StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done
Goto loop
found:
StrCpy $STR_RETURN_VAR $STR_NEEDLE
Goto done
done:
Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the
Exch $STR_RETURN_VAR
FunctionEnd
!macro _StrContainsConstructor OUT NEEDLE HAYSTACK
Push `${HAYSTACK}`
Push `${NEEDLE}`
Call StrContains
Pop `${OUT}`
!macroend
!define StrContains '!insertmacro "_StrContainsConstructor"'
;--------------------------------
; Start sections
Section "MyApp" SEC1
;MessageBox MB_OK "SEC1 #1 INSTDIR is $INSTDIR"
${StrContains} $0 "MyApp" "$INSTDIR"
;MessageBox MB_OK "SEC1 #2 0 is $0"
StrCmp $0 "" notfoundMyApp
StrCpy $MyAppInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #3 MyAppInstallDir is $MyAppInstallDir"
Goto doneMyApp
notfoundMyApp:
;MessageBox MB_OK 'Did not find MyApp string'
doneMyApp:
${StrContains} $0 "Flex" "$INSTDIR"
StrCmp $0 "" notfoundFlex
StrCpy $FlexLmInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #4 FlexLmInstallDir is $FlexLmInstallDir"
Goto doneFlex
notfoundFlex:
;MessageBox MB_OK 'Did not find Flex string'
##All the files in Group 1 will be installed to the same location, $INSTDIR
SetOutPath "$INSTDIR"
File MyApp.exe
File ReleaseNotes.txt
File MyCompany_LandingPage_114.bmp
File MyAppLicense.txt
# create a shortcut named "new shortcut" in the start menu programs directory
CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$InstDir\${PRODUCT_NAME}.exe"
# Add application to registry
ClearErrors
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'Company Name' "${COMPANY_NAME}"
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'Version' "${PRODUCT_VERSION}"
WriteRegStr HKCU "SOFTWARE\${PRODUCT_NAME}" 'AppID' "{A0E84732-E2B2-46E5-8CA2-462B8DF92DCD}"
# Add program to Add/Remove programs
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayIcon" "$PROGRAMFILES64\${PRODUCT_NAME}\${PRODUCT_NAME}.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"AppID" "{A0E84732-E2B2-46E5-8CA2-462B8DF92DCD}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"Publisher" "${COMPANY_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"UninstallString" "$\"$INSTDIR\uninstaller.exe$\""
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
doneFlex:
# messagebox mb_ok sec1
SectionEnd
Section "FlexLM" SEC3
;MessageBox MB_OK "SEC3 #1 INSTDIR is $INSTDIR"
;MessageBox MB_OK "SEC1 #1 INSTDIR is $INSTDIR"
${StrContains} $0 "Pro" "$INSTDIR"
;MessageBox MB_OK "SEC1 #2 0 is $0"
StrCmp $0 "" notfoundMyApp
StrCpy $MyAppInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #3 MyAppInstallDir is $MyAppInstallDir"
Goto doneMyApp
notfoundMyApp:
;MessageBox MB_OK 'Did not find MyApp string'
${StrContains} $0 "Flex" "$INSTDIR"
StrCmp $0 "" notfoundFlex
StrCpy $FlexLmInstallDir "$INSTDIR"
;MessageBox MB_OK "SEC1 #4 FlexLmInstallDir is $FlexLmInstallDir"
Goto doneFlex
notfoundFlex:
;MessageBox MB_OK 'Did not find Flex string'
doneFlex:
##All the files in Group 2 will be installed to the same location, $INSTDIR
SetOutPath "$INSTDIR"
File installs.exe
File lmdown.exe
File lmflex.exe
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
doneQI:
# messagebox mb_ok sec3
SectionEnd
;--------------------------------
;Descriptions
;Language strings
LangString DESC_SecMyApp ${LANG_ENGLISH} "MyAppTM software is an easy-to-use suite of tools."
LangString DESC_SecFlexLM ${LANG_ENGLISH} "FlexSQI contains all the files necessary to implement the FlexLM license server."
;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC1} $(DESC_SecMyApp)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC3} $(DESC_SecFlexLM)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section "Uninstall"
# Always delete uninstaller first
Delete $INSTDIR\uninstaller.exe
# now delete installed files and registry keys for MyApp
Delete $INSTDIR\config.dat
Delete $INSTDIR\MyApp.exe
Delete $INSTDIR\ReleaseNotes.txt
Delete $INSTDIR\MyCompany_LandingPage_114.bmp
Delete $INSTDIR\MyAppLicense.txt
Delete "$SMPROGRAMS\MyApp.lnk"
DeleteRegKey HKCU "SOFTWARE\${PRODUCT_NAME}"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
DeleteRegKey /ifempty HKCU "Software\Modern UI Test"
# now delete installed files and registry keys for FlexLM
Delete $INSTDIR\installs.exe
Delete $INSTDIR\lmborrow.exe
Delete $INSTDIR\lmflex.exe
# Delete the MyApp and FlexLM directories
RMDir $INSTDIR
SectionEnd
;--------------------------------
; Please don`t modify below here unless you`re a NSIS 'wiz-kid'
## Create $PLUGINSDIR
Function .onInit
InitPluginsDir
SetOutPath $TEMP
File /oname=spltmp.bmp "MyCompany_LandingPage_114.bmp"
splash::show 2000 $TEMP\spltmp
Pop $0 ; $0 has '1' if the user closed the splash screen early,
; '0' if everything closed normally, and '-1' if some error occurred.
Delete $TEMP\spltmp.bmp
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
StrCpy $R0 ${PROG1_StartIndex} # Group 1 start
SectionGetFlags 0 $R0 # Get section flags
IntOp $R0 $R0 & ${SF_SELECTED}
StrCmp $R0 ${SF_SELECTED} 0 +3 # If section is selected, done
StrCpy $R0 1
Exch $R0
FunctionEnd
Function IsPROG2Selected
Push $R1
StrCpy $R1 ${PROG2_StartIndex} # Group 2 start
IntOp $R1 $R1 + 1
SectionGetFlags 1 $R1 # Get section flags
IntOp $R1 $R1 & ${SF_SELECTED}
StrCmp $R1 ${SF_SELECTED} 0 +3 # If section is selected, done
StrCpy $R1 1
Exch $R1
FunctionEnd
## Here we are selecting first sections to install
## by unselecting all the others!
Function SelectFilesA
${If} ${SectionIsSelected} ${SEC1}
;MessageBox MB_OK "SEC1 #1 INSTDIR is $INSTDIR"
${Else}
Abort
${EndIf}
# 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
${If} ${SectionIsSelected} ${SEC3}
;MessageBox MB_OK "SEC1 #3 INSTDIR is $INSTDIR"
${Else}
Abort
${EndIf}
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
## Here we are deleting the temp INI file at the end of installation
Function DeleteSectionsINI
FlushINI "$PLUGINSDIR\Sections.ini"
Delete "$PLUGINSDIR\Sections.ini"
# FlexLM libs
;MessageBox MB_OK "DeleteSectionsINI #1 MyAppInstallDir is $MyAppInstallDir"
Delete $MyAppInstallDir\installs.exe
Delete $MyAppInstallDir\lmborrow.exe
# QI Pro files
;MessageBox MB_OK "DeleteSectionsINI #1 FlexLmInstallDir is $FlexLmInstallDir"
Delete $FlexLmInstallDir\config.dat
Delete $FlexLmInstallDir\MyApp.exe
Delete $FlexLmInstallDir\ReleaseNotes.txt
Delete $FlexLmInstallDir\MyApp_LandingPage_114.bmp
Delete $FlexLmInstallDir\MyAppLicense.txt
FunctionEnd

NSIS: call MUI_PAGE_LICENSE from function but get "XPStyle not valid" error

I have a custom dialog with an "License terms and conditions." checkbox where the Text to the checkbox is actually a link which is suppose to show the License Dialog.
; === LicenseLink (type: Link) ===
${NSD_CreateLink} 132.96u 100.92u 107.29u 14.15u "License terms and conditions."
Pop $hCtl_welcome_LicenseLink
${NSD_OnClick} $hCtl_welcome_LicenseLink ShowLicense
Now in the function "ShowLicense" I tried calling
!insertmacro MUI_PAGE_LICENSE
but get an error:
Error: command XPStyle not valid in Function
evidently I'm approaching this wrong and I can't interpret the error. Would be happy for any ideas on how to resolve this.
Thanks!
You cannot call !insertmacro MUI_PAGE_LICENSE dynamically, the number of pages is determined at compile time.
You can however skip pages to achieve this:
InstallDir "$Temp\Test"
!include MUI2.nsh
!include nsDialogs.nsh
!include WinMessages.nsh
!include LogicLib.nsh
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipLicensePage
!insertmacro MUI_PAGE_LICENSE "${__FILE__}"
Page Custom InfoPageCreate InfoPageValidate
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE English
Var ShowLicensePage
Function SkipLicensePage
${IfThen} $ShowLicensePage = 0 ${|} Abort ${|} ; Skip it the first time
FunctionEnd
Function OnShowLicense
SendMessage $hWndParent ${WM_COMMAND} 3 "" ; Click the (hidden) back button
FunctionEnd
Var InstDirCtl
Function InfoPageCreate
StrCpy $ShowLicensePage 1
GetDlgItem $0 $hWndParent 3
ShowWindow $0 0 ; Hide the back button
!insertmacro MUI_HEADER_TEXT "Blah blah" "blah blah blah"
nsDialogs::Create 1018
Pop $0
${NSD_CreateText} 0 13u 100% 12u "$InstDir"
Pop $InstDirCtl
${NSD_CreateLink} 2u 40u -4u 12u "License"
Pop $0
${NSD_OnClick} $0 OnShowLicense
nsDialogs::Show
FunctionEnd
Function InfoPageValidate
${NSD_GetText} $InstDirCtl $InstDir
FunctionEnd

How to move NSD_OnBack function from the section in NSIS

I'm writing an NSIS script, in this using some sections to execute EXE files. on depending output, I need to go back from the section to other custom pages but here nsis is moving to another section even though keeping of NSD_OnBack function or just calling the particular function
I have tried below 2 methods.
${NSD_OnBack} "callbackfunction"
call callbackfunction
//Section started
Section "validation" VALIDATION
DetailPrint "Executing Validation"
File "Folder_name\Validation.exe"
nsExec::Exec '"$INSTDIR\Validation.exe" $arg1 $arg2 $arg3'
IfFileExists "$INSTDIR\Output.txt" pass fail
pass:
FileOpen $chk "$INSTDIR\Output.txt" r
FileRead $chk $1
MessageBox MB_OK|MB_ICONSTOP "Validation_Output : in 1 $1"
Push $1
Push "true"
Call StrContains
Pop $3
${If} $3 == "true"
call someotherfunction
${ELSE}
goto fail
${ENDIF}
FileClose $chk
Delete $chk
fail:
MessageBox MB_OK|MB_ICONSTOP "fail"
//Here this call is not working
${NSD_OnBack} "callbackfunction"
SectionEnd
Function callbackfunction
GetDlgItem $0 $HWNDPARENT 2
${IF} $portalname == "centralised"
${IF} $username == ""
call CentralisedPage
${ENDIF}
${ELSE}
${IF} $username == ""
call SetCustom
${ENDIF}
${ENDIF}
Functionend
I am expecting to move other page based on EXE results.
${NSD_OnBack} is a callback for nsDialogs custom pages and it is invoked when the user presses the back button on that page, it is not relevant here.
Ideally you should collect all information before you get to the InstFiles page but if you can't do that then I would recommend that you just show a custom page after the InstFiles page if required.
If you absolutely need to execute sections multiple times you can use more than one InstFiles page:
!include LogicLib.nsh
!include WinMessages.nsh
!include nsDialogs.nsh
!include Sections.nsh
!include MUI2.nsh
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_PRE Init1stStage
!insertmacro MUI_PAGE_INSTFILES
Page Custom MyCustomPageCreate
!define MUI_PAGE_CUSTOMFUNCTION_PRE Init2ndStage
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE English
Var Needs2ndStage
Section "1st stage" SID_1
DetailPrint "1st stage"
MessageBox mb_yesno "Needs 2nd stage?" IDNO nope
StrCpy $Needs2ndStage 1
nope:
SectionEnd
Section "-2nd stage" SID_2
DetailPrint "2nd stage"
SectionEnd
Function Init1stStage
!insertmacro UnselectSection ${SID_2}
FunctionEnd
Function Init2ndStage
!insertmacro UnselectSection ${SID_1}
${IfThen} $Needs2ndStage = 0 ${|} Abort ${|}
FunctionEnd
Function MyCustomPageCreate
${IfThen} $Needs2ndStage = 0 ${|} Abort ${|}
!insertmacro SelectSection ${SID_2}
GetDlgItem $0 $hWndParent 1
SendMessage $0 ${WM_SETTEXT} "" "STR:C&ontinue"
GetDlgItem $0 $hWndParent 3
ShowWindow $0 0 ; Hide back
GetDlgItem $0 $hWndParent 2
EnableWindow $0 0 ; Disable cancel
!insertmacro MUI_HEADER_TEXT "Blah" "Blah blah blah"
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 0 100% 12u "Enter blah blah before you can enter the 2nd stage"
Pop $0
nsDialogs::Show
FunctionEnd

When I am clicking on "Finish" button or close button at the top right corner of the custom page, page is not closing using NSIS

I am facing a weird problem, I have added a new custom page (MyAbruptPage). When clicking on "Finish" button or close button at the top right corner of this custom page, page is not closing.
Scenario:
When Installing the software, if something went wrong and installation hasn't done properly it shows a MessageBox from INSTFILES page. Upon click on "OK" on the message box It is navigating to the "Abrupt" page. In the Abrupt Page it is showing "Finish" button, but when clicked on "Finish" the page is not closing instead it is showing a pop-up message (Are you sure you want to close?). Even when i clicked on close button in the top right corner also i am getting the same pop-up message. I don't want that message and the dialog should be closed when clicked on "Finish" button.
Observations:
I am thinking that the problem is due to the sequence of the pages. Because here i have used two custom pages (MyInfoPage, And MyAbruptPage).
If I replace the first page (MyInfoPage) with MyAbruptPage. Then I am not seeing any issue when clicking on "Finish" button in the Abrupt Page.
Below is my code snippet showing pages and its sequence:
Page Custom MyInfoPage ; First Custom page
!define MUI_PAGE_CUSTOMFUNCTION_SHOW WelShow
!insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyLicenseShowCallback
!insertmacro MUI_PAGE_LICENSE
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyDirectoryShowCallback
!insertmacro MUI_PAGE_DIRECTORY
Page Custom MyAbruptPage ; Second Custom Page
!define MUI_PAGE_CUSTOMFUNCTION_SHOW AbruptShow
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE AbruptLeave
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
; Below is my code for the Abrupt page
Function AbruptShow
StrCpy $IsOnAbruptPage 1
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0
FunctionEnd
Function AbruptLeave
StrCpy $IsOnAbruptPage 0
FunctionEnd
Function MyAbruptPage
${IfThen} $IsOnAbruptPage == "" ${|} Abort ${|}
GetDlgItem $0 $HWNDPARENT 1
ShowWindow $0 0 ; Hide Next button
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0 ; Hide Back button
GetDlgItem $0 $HWNDPARENT 2
${NSD_SetText} $0 "Finish"
nsDialogs::Create 1044
Pop $0
${NSD_CreateLabel} 120u 10u 195u ${MUI_WELCOMEPAGE_TITLE_HEIGHT}u "$(AbruptTitle)"
Pop $AbruptPageTitle
;SetCtlColors $InterruptPageTitle "" "${MUI_BGCOLOR}"
CreateFont $AbruptPageFont "$(^Font)" "12" "700"
SendMessage $AbruptPageTitle ${WM_SETFONT} $AbruptPageFont 0
${NSD_CreateLabel} 120u ${MUI_WELCOMEPAGE_TEXT_TOP}u 195u 130u "$(AbruptText)"
Pop $AbruptPageText
Pop $0
nsDialogs::Show
${NSD_FreeImage} $ImageHandle
FunctionEnd
Below is the section and from here Message box is popping up and navigating to the Abrupt screen:
;!insertmacro MUI_LANGUAGE "English"
Section MySection
SetOutPath $INSTDIR
MessageBox MB_OK|MB_ICONEXCLAMATION "Installation hasn't done properly" IDOK
Call AbruptLeave
SendMessage $HWNDPARENT 0x408 -1 ""
Abort
SectionEnd
;Below is the code for the custompage "MyInfoPage"
Function MyInfoPage
${IfThen} $PageId == "" ${|} Abort ${|}
StrCpy $PageId 0
GetDlgItem $0 $HWNDPARENT 1
ShowWindow $0 0 ; Hide Next button
GetDlgItem $0 $HWNDPARENT 2
${NSD_SetText} $0 "Finish"
nsDialogs::Create 1044
Pop $0
${NSD_CreateLabel} 120u 10u 195u ${MUI_WELCOMEPAGE_TITLE_HEIGHT}u "$(InterruptTitle)"
Pop $InterruptPageTitle
${NSD_CreateLabel} 120u ${MUI_WELCOMEPAGE_TEXT_TOP}u 195u 130u "$(InterruptText)"
Pop $InterruptPageText
nsDialogs::Show
${NSD_FreeImage} $ImageHandle
FunctionEnd
Function WelShow
StrCpy $PageId 1
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0 ; Hide Back button
FunctionEnd
Function onAbort
${If} $PageId <> 0
${If} ${Cmd} ` MessageBox MB_YESNO "Are you sure you want to close?" IDYES `
SendMessage $HWNDPARENT 0x408 -$PageId ""
${EndIf}
Abort
${EndIf}
FunctionEnd
I have tried by changing the sequence of the pages and every time I am observing different behaviors in both the custom pages. Please help me how to resolve this issue? And the correct way to implement this functionality.
Thank you in advance...
Below is the complete code and it is compiling:
Var PageId
Var PrintBtn
Var Image
Var ImageHandle
Var MyInfoPageTitle
Var MyInfoPageFont
var MyInfoPageText
var IsOnAbruptPage
Var AbruptPageTitle
Var AbruptPageFont
var AbruptPageText
!define MUI_CUSTOMFUNCTION_ABORT onAbort
!include "MUI2.nsh"
!include x64.nsh
Name "MyApp"
OutFile "MyApp.exe"
InstallDir "$PROGRAMFILES32\MyApp"
InstallDirRegKey HKLM "Software\MyApp" "Install_Dir"
RequestExecutionLevel admin
!include LogicLib.nsh
;--------------------------------
Page Custom MyInfoPage
!define MUI_PAGE_CUSTOMFUNCTION_SHOW WelShow
!define MUI_TEXT_WELCOME_INFO_TITLE $(welcometitle)
!define MUI_TEXT_WELCOME_INFO_TEXT $(welcometext)
!insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyLicenseShowCallback
!define MUI_LICENSEPAGE_CHECKBOX ""
!define MUI_INNERTEXT_LICENSE_BOTTOM ""
!define MUI_INNERTEXT_LICENSE_TOP ""
!define MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX ""
!define MUI_TEXT_LICENSE_TITLE $(licensetitle)
!define MUI_TEXT_LICENSE_SUBTITLE $(licensesubtitle)
!define MUI_LICENSEPAGE_CHECKBOX_TEXT $(licensecheckboxtext)
!insertmacro MUI_PAGE_LICENSE "C:\Program Files (x86)\NSIS\Docs\Modern UI 2\license.txt"
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyDirectoryShowCallback
!define MUI_DIRECTORYPAGE_TEXT_TOP $(mydirtoptext)
!define MUI_TEXT_DIRECTORY_TITLE $(mydirtitle)
!define MUI_TEXT_DIRECTORY_SUBTITLE $(mydirsubtitle)
!insertmacro MUI_PAGE_DIRECTORY
Page Custom MyAbruptPage
!define MUI_PAGE_CUSTOMFUNCTION_SHOW AbruptShow
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE AbruptLeave
!insertmacro MUI_PAGE_INSTFILES
!define MUI_TEXT_FINISH_INFO_TITLE $(Finishpagetitle)
!define MUI_TEXT_FINISH_INFO_TEXT $(Finishpagesubtitle)
!define MUI_FINISHPAGE_RUN ""
!define MUI_FINISHPAGE_RUN_TEXT $(FinishonlineReg)
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_INSTFILES
;--------------------------------
!insertmacro MUI_LANGUAGE "English"
Function .onInit
InitPluginsDir
FunctionEnd
Function MyDirectoryShowCallback
StrCpy $PageId 3
GetDlgItem $0 $hwndparent 1 ;
SendMessage $0 ${WM_SETTEXT} 0 `STR:$(^NextBtn)`
FunctionEnd
Function MyLicenseShowCallback
StrCpy $PageId 2
GetDlgItem $0 $hwndparent 2
System::Call *(i,i,i,i)p.r1
System::Call 'USER32::GetWindowRect(pr0,pr1)'
System::Call *$1(i.r2,i.r3,i.r4,i.r5)
IntOp $5 $5 - $3 ;height
IntOp $4 $4 - $2 ;width
System::Call 'USER32::ScreenToClient(p$hwndparent,pr1)'
System::Call *$1(i.r2,i.r3)
System::Free $1
IntOp $2 $4 / 5
System::Call 'USER32::CreateWindowEx(i 0,t "Button",t "Print",i ${WS_CHILD}|${WS_VISIBLE}|${WS_TABSTOP},i r2,i r3,i r4,i r5,p $hwndparent,p 0x666,p 0,p 0)p.r0'
StrCpy $PrintBtn $0
SendMessage $hwndparent ${WM_GETFONT} 0 0 $1
SendMessage $0 ${WM_SETFONT} $1 1
ButtonEvent::AddEventHandler 0x666 $0
FunctionEnd
Function WelShow
StrCpy $PageId 1
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0
FunctionEnd
Function MyInfoPage
${IfThen} $PageId == "" ${|} Abort ${|}
StrCpy $PageId 0
GetDlgItem $0 $HWNDPARENT 1
ShowWindow $0 0
GetDlgItem $0 $HWNDPARENT 2
${NSD_SetText} $0 "Finish"
nsDialogs::Create 1044
Pop $0
!define MUI_WELCOMEPAGE_TITLE_HEIGHT 38
!define /math MUI_WELCOMEPAGE_TEXT_TOP 17 + ${MUI_WELCOMEPAGE_TITLE_HEIGHT}
${NSD_CreateLabel} 120u 10u 195u 28u "Setup Wizard was interrupted"
Pop $MyInfoPageTitle
CreateFont $MyInfoPageFont "$(^Font)" "12" "700"
SendMessage $MyInfoPageTitle ${WM_SETFONT} $MyInfoPageFont 0
${NSD_CreateLabel} 120u ${MUI_WELCOMEPAGE_TEXT_TOP}u 195u 130u "Setup Wizard was interrupted"
Pop $MyInfoPageText
Pop $0
nsDialogs::Show
${NSD_FreeImage} $ImageHandle
FunctionEnd
Function onAbort
${If} $PageId <> 0
${If} ${Cmd} ` MessageBox MB_YESNO "Are you sure you want to CANCEL" IDYES `
SendMessage $HWNDPARENT 0x408 -$PageId ""
${EndIf}
Abort
${EndIf}
FunctionEnd
Function AbruptShow
StrCpy $IsOnAbruptPage 1
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0
FunctionEnd
Function AbruptLeave
StrCpy $IsOnAbruptPage 0
FunctionEnd
Function MyAbruptPage
${IfThen} $IsOnAbruptPage == "" ${|} Abort ${|}
GetDlgItem $0 $HWNDPARENT 1
ShowWindow $0 0
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0
GetDlgItem $0 $HWNDPARENT 2
${NSD_SetText} $0 "Finish"
nsDialogs::Create 1044
Pop $0
${NSD_CreateLabel} 120u 10u 195u ${MUI_WELCOMEPAGE_TITLE_HEIGHT}u "Setup Wizard ended prematurely"
Pop $AbruptPageTitle
CreateFont $AbruptPageFont "$(^Font)" "12" "700"
SendMessage $AbruptPageTitle ${WM_SETFONT} $AbruptPageFont 0
${NSD_CreateLabel} 120u ${MUI_WELCOMEPAGE_TEXT_TOP}u 195u 130u "Setup Wizard ended prematurely"
Pop $AbruptPageText
Pop $0
nsDialogs::Show
${NSD_FreeImage} $ImageHandle
FunctionEnd
SectionIn RO
SetOutPath $INSTDIR
MessageBox MB_OK|MB_ICONEXCLAMATION "There is an installation failure. Aborting the installation process" IDOK
Call AbruptLeave
SendMessage $HWNDPARENT 0x408 -1 ""
Abort
SectionEnd
Section "Uninstall"
SectionEnd
The MessageBox you see is coming from your own code in your onAbort function!
The fact that you are doing
!define MUI_PAGE_CUSTOMFUNCTION_SHOW AbruptShow
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE AbruptLeave
shows that you have don't understand how custom pages work.
To make your special abort page quit without further action you simple have to do nothing in your onAbort function when you are on that page:
Var PageId
var IsOnAbruptPage
!define MUI_CUSTOMFUNCTION_ABORT onAbort
!include "MUI2.nsh"
!include LogicLib.nsh
Name "MyApp"
#OutFile "MyApp.exe"
InstallDir "$temp\MyApp"
#RequestExecutionLevel admin
OutFile Test.exe
RequestExecutionLevel user
;--------------------------------
Page Custom MyInfoPage
!define MUI_PAGE_CUSTOMFUNCTION_SHOW WelShow
!insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyLicenseShowCallback
!insertmacro MUI_PAGE_LICENSE "${__FILE__}"
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyDirectoryShowCallback
!insertmacro MUI_PAGE_DIRECTORY
Page Custom MyAbruptPage
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
;--------------------------------
!insertmacro MUI_LANGUAGE "English"
Function MyDirectoryShowCallback
StrCpy $PageId 3
GetDlgItem $0 $hwndparent 1 ;
SendMessage $0 ${WM_SETTEXT} 0 `STR:$(^NextBtn)`
FunctionEnd
Function MyLicenseShowCallback
StrCpy $PageId 2
FunctionEnd
Function WelShow
StrCpy $PageId 1
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0
FunctionEnd
Function MyInfoPage
${IfThen} $PageId == "" ${|} Abort ${|}
StrCpy $PageId 0
GetDlgItem $0 $HWNDPARENT 1
ShowWindow $0 0
GetDlgItem $0 $HWNDPARENT 2
${NSD_SetText} $0 "Finish"
nsDialogs::Create 1044
Pop $0
${NSD_CreateLabel} 120u 10u 195u 28u "Setup Wizard was interrupted"
Pop $0
nsDialogs::Show
FunctionEnd
Function onAbort
${If} $IsOnAbruptPage <> 0 ; If on aborted page
Return ; allow simple exit
${EndIf}
${If} $PageId <> 0
${If} ${Cmd} ` MessageBox MB_YESNO "Are you sure you want to CANCEL" IDYES `
SendMessage $HWNDPARENT 0x408 -$PageId ""
${EndIf}
Abort
${EndIf}
FunctionEnd
Function GoToAbruptPage
StrCpy $IsOnAbruptPage 1
SendMessage $HWNDPARENT 0x408 -1 ""
Abort
FunctionEnd
Function MyAbruptPage
${IfThen} $IsOnAbruptPage == "" ${|} Abort ${|}
GetDlgItem $0 $HWNDPARENT 1
ShowWindow $0 0
GetDlgItem $0 $HWNDPARENT 3
ShowWindow $0 0
GetDlgItem $0 $HWNDPARENT 2
${NSD_SetText} $0 "Finish"
nsDialogs::Create 1044
Pop $0
${NSD_CreateLabel} 120u 10u 195u 20u "Setup Wizard ended prematurely"
Pop $0
${NSD_CreateLabel} 120u 120u 195u 20u "Setup Wizard ended prematurely"
Pop $0
nsDialogs::Show
FunctionEnd
;--------------------------------
Section "$(^Name) (required)"
SectionIn RO
SetOutPath $INSTDIR
MessageBox MB_OK|MB_ICONEXCLAMATION "There is an installation failure. Aborting the installation process" IDOK
Call GoToAbruptPage
SectionEnd

Increase buffer size for "Writeinistr" in nsis

I am new for nsis
Created ini page which contains "Text" type, using this type i was showing the some dynamic data in the label. The size of file is 2 kb, so i need to increase the size for "State" option in "Text" type. So how to increase the size of State using writeinistr?
To bypass the NSIS string length limitation you have to call the Windows API directly:
Page Custom MyPage
Page InstFiles
!macro IniWriteAsciiStringPtr ini sec name strptr
!if "${NSIS_CHAR_SIZE}" > 1
Push $0
Push $1
Push $2
Push "${ini}"
Push "${name}"
Push "${sec}"
StrCpy $0 ${strptr}
System::Call 'kernel32::MultiByteToWideChar(i0, i0, i$0, i-1, i0, i0)i.r2'
System::Call '*(&w$2)i.r1'
System::Call 'kernel32::MultiByteToWideChar(i0, i0, i$0, i-1, ir1, ir2)'
System::Call 'kernel32::WritePrivateProfileString(t s, t s, ir1, t s)'
System::Free $1
Pop $2
Pop $1
Pop $0
!else
System::Call 'kernel32::WritePrivateProfileString(t "${sec}", t "${name}", i ${strptr}, t "${ini}")'
!endif
!macroend
!include InstallOptions.nsh
Function MyPage
InitPluginsDir
; Building the entire .ini at run-time in this example
WriteIniStr "$PluginsDir\io.ini" Settings NumFields 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Type Text
WriteIniStr "$PluginsDir\io.ini" "Field 1" Left 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Right -2
WriteIniStr "$PluginsDir\io.ini" "Field 1" Top 5
WriteIniStr "$PluginsDir\io.ini" "Field 1" Bottom -10
WriteIniStr "$PluginsDir\io.ini" "Field 1" Flags MULTILINE
FileOpen $0 "$PluginsDir\test.txt" r
FileSeek $0 0 END $1
FileSeek $0 0 SET
System::Call '*(&i$1,i0)i.r2'
System::Call 'kernel32::ReadFile(ir0,ir2,ir1,*i,i0)'
!insertmacro IniWriteAsciiStringPtr "$PluginsDir\io.ini" "Field 1" "State" $2
System::Free $2
FileClose $0
!insertmacro INSTALLOPTIONS_DISPLAY "io.ini"
FunctionEnd
Function .onInit
InitPluginsDir
; Create a big file for this example
FileOpen $0 "$PluginsDir\test.txt" w
StrCpy $2 0
loop:
StrCmp $2 2048 done
IntOp $1 $2 % 10
StrCmp $2 2047 0 +2
StrCpy $1 "!"
FileWrite $0 $1
IntOp $2 $2 + 1
Goto loop
done:
FileClose $0
FunctionEnd
You can also bypass the .ini and set it directly in the dialog:
Page Custom MyPage
Page InstFiles
!include InstallOptions.nsh
!include WinMessages.nsh
Function MyPage
InitPluginsDir
; Building the entire .ini at run-time in this example
WriteIniStr "$PluginsDir\io.ini" Settings NumFields 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Type Text
WriteIniStr "$PluginsDir\io.ini" "Field 1" Left 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Right -2
WriteIniStr "$PluginsDir\io.ini" "Field 1" Top 5
WriteIniStr "$PluginsDir\io.ini" "Field 1" Bottom -10
WriteIniStr "$PluginsDir\io.ini" "Field 1" Flags MULTILINE
FileOpen $0 "$PluginsDir\test.txt" r
FileSeek $0 0 END $1
FileSeek $0 0 SET
System::Call '*(&i$1,i0)i.r2'
System::Call 'kernel32::ReadFile(ir0,ir2,ir1,*i,i0)'
FileClose $0
!insertmacro INSTALLOPTIONS_INITDIALOG "io.ini"
Pop $0
!insertmacro INSTALLOPTIONS_READ $0 "io.ini" "Field 1" "HWND"
!if "${NSIS_CHAR_SIZE}" > 1
!error TODO
!else
SendMessage $0 ${WM_SETTEXT} 0 $2
!endif
System::Free $2
!insertmacro INSTALLOPTIONS_SHOW
FunctionEnd
Function .onInit
InitPluginsDir
; Create a big file for this example
FileOpen $0 "$PluginsDir\test.txt" w
StrCpy $2 0
loop:
StrCmp $2 2048 done
IntOp $1 $2 % 10
StrCmp $2 2047 0 +2
StrCpy $1 "!"
FileWrite $0 $1
IntOp $2 $2 + 1
Goto loop
done:
FileClose $0
FunctionEnd

Resources