首页 > 解决方案 > 为什么我的 nsis 脚本选择文件夹对话框没有出现?

问题描述

这里不明白为什么如果只选择MyApp它不允许用户选择目录。对于每个程序,MUI_PAGE_DIRECTORY宏是它指示用户应该选择目录的地方,SelectFilesMyApp显然有,所以我不确定为什么如果用户只选择该程序,它不允许他们选择自定义目录. MyPartnerApp Plugin如果他们选择所有程序,则用户可以为每个程序选择一个自定义MyApp导演LicenseManager

这是完整的脚本,部分基于https://nsis.sourceforge.io/Two_installations_in_one_installer

!include "LogicLib.nsh"

;Include Modern UI
!include "MUI2.nsh"
!include "Sections.nsh"
!include "winmessages.nsh"

!define MAJOR_VERSION "1" 
!define MINOR_VERSION "2" 
!define PATCH_VERSION "3" 
!define BUILD_VERSION "4" 
    
!define APP_COPYRIGHT "MyApp © My Company 2021"
!define COMPANY_NAME "MyCompany"
!define LICENSE_APP "MyLicenseApp"        
!define LM_DIR "LicenseManagerSMyApp"     
!define HW_DATA "HW-Data"
!define HW_WORKSPACE "HW-Workspaces"        
!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 "My Company"

OutFile ${SETUP_NAME}
Icon "favicon.ico"
UninstallIcon "favicon.ico"
!define MUI_ICON "favicon.ico"
!define MUI_UNICON "favicon.ico"
Name "${PRODUCT_NAME}"
    
InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}\"
InstallDirRegKey HKLM "Software\$PRODUCT_NAME" ""
ShowInstDetails hide
ShowUnInstDetails hide

SetCompressor /SOLID lzma
SetCompressorDictSize 12

;Request application privileges for Windows 
RequestExecutionLevel admin

; HKLM (all users) vs HKCU (current user) defines
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!define env_hkcu 'HKCU "Environment"'

!macro WriteSignedUninstaller Destination
!makensis '"/DGENRATINGUNINST=$%TEMP%\Uninst.exe" "${__FILE__}" "/XOutfile `$%TEMP%\tempinstaller.exe`"' = 0 ; Create fake installer
!system 'set __COMPAT_LAYER=RunAsInvoker&"$%TEMP%\tempinstaller.exe"' = 2 ; Run fake installer to generate the uninstaller
!system 'SIGNTOOL sign /f ../CodeSigningCertificate/MyCompanySolutions.pfx /p MyCertPassword /tr http://timestamp.digicert.com /td SHA256 "$%TEMP%\Uninst.exe"' = 0 ; Change this line. As a demonstration, use !system 'echo Dummy >> "$%TEMP%\Uninst.exe"'
File "/oname=${Destination}" "$%TEMP%\Uninst.exe"
!macroend

!macro DeclareLanguages
!insertmacro MUI_LANGUAGE English
!macroend

!ifndef GENRATINGUNINST
Var MyPartnerAppInstallDir
Var MyAppInstallDir
Var LicenseManagerLmInstallDir

# Installer:
############
!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 MyPartnerApp Data Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_HW)"
!define MUI_PAGE_HEADER_TEXT "Choose MyPartnerApp Data directory"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder which MyPartnerApp can use as a data storage."

;Directory for MyPartnerApp files and where config.dat will point to
Var HW_DATA_DIR
Var HW_WORKSPACE_DIR

; HW Data 
!define MUI_PAGE_CUSTOMFUNCTION_PRE hw_data_pre
!define MUI_PAGE_CUSTOMFUNCTION_SHOW hw_data_dir
!define MUI_DIRECTORYPAGE_VARIABLE $HW_DATA_DIR
!insertmacro MUI_PAGE_DIRECTORY

## This is the title on the MyPartnerApp Workspace Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_HW_WK)"
!define MUI_PAGE_HEADER_TEXT "Choose MyPartnerApp Workspace directory"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder which MyPartnerApp can use as a workspace."

# HW Workspaces
!define MUI_PAGE_CUSTOMFUNCTION_PRE hw_wk_pre
!define MUI_PAGE_CUSTOMFUNCTION_SHOW hw_wk_dir 
!define MUI_DIRECTORYPAGE_VARIABLE $HW_WORKSPACE_DIR
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES    
 
## This is the title on the MyPartnerApp installation Directory page to obtain directory for %HEADWAVE_ROOT_DIR
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_HW_INST)"
!define MUI_PAGE_HEADER_TEXT "Choose MyPartnerApp Plugin installation directory"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder where MyPartnerApp is presently installed to set environment variable."
 
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesMyPartnerAppProg
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES

## This is the title on the MyApp Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_A)"
!define MUI_PAGE_HEADER_TEXT "Choose Install Location"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder in which to install MyApp."
 
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesMyApp
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES

## This is the title on the MyLicenseApp Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_B)"
!define MUI_PAGE_HEADER_TEXT "Choose Install Location"
!define MUI_PAGE_HEADER_SUBTEXT "Please choose the folder in which to install MyLicenseApp."
 
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesMyLicenseApp
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
 
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE DeleteSectionsINI
!define MUI_FINISHPAGE_TEXT "In MyPartnerApp, select File/User preferences:$\n$\nOutput directory = $HW_DATA_DIR$\n$\nCompute plugin directories = $HW_DATA_DIR\MyApp-Plugins\ComputePlugin$\n$\nExtension plugin directories = $HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin$\n$\nThe MyApp to MyPartnerApp connector uses network port 8080 by default. If this is a conflict on your system you can specify a new port by editing both the config.dat and MyAppConfig.py files with a new port number."
!insertmacro MUI_PAGE_FINISH
!insertmacro DeclareLanguages
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

;--------------------------------

LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!"

LangString MUI_DIRECTORYPAGE_TEXT_TOP_HW ${LANG_ENGLSH} "Select \
${HW_DATA} installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_HW_WK ${LANG_ENGLSH} "Select \
${HW_WORKSPACE} installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_HW_INST ${LANG_ENGLSH} "Select \
MyPartnerApp installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Select \
${PRODUCT_NAME} installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Select \
${LICENSE_APP} installation location..."

;--------------------------------
; Settings
 
!define PROG1_InstDir    "$PROGRAMFILES64"
!define PROG1_StartIndex ${SEC1}
!define PROG1_EndIndex   ${SEC1}
 
!define PROG2_InstDir    "$PROGRAMFILES64\${PRODUCT_NAME}"
!define PROG2_StartIndex ${SEC2}
!define PROG2_EndIndex   ${SEC2}
 
!define PROG3_InstDir "C:\${LM_DIR}"
!define PROG3_StartIndex ${SEC3}
!define PROG3_EndIndex   ${SEC3}

;--------------------------------
; StrContains   
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 1
Section "MyPartnerApp Plugin" SEC1
  ${If} ${SectionIsSelected} ${SEC1}    
    ${StrContains} $0 "MyPartnerApp" "$INSTDIR" 
    StrCmp $0 "" notfoundMyPartnerApp
    Goto doneMyPartnerApp
    doneMyPartnerApp:
      SetOutPath "$HW_DATA_DIR"
      ${StrContains} $0 "Data" "$HW_DATA_DIR"
      StrCmp $0 "" notfoundHwData
      Goto doneHwData
    doneHwData: 
    
      ##All the files in Group 0 will be installed to the same location, $HW_DATA_DIR
      SetOutPath "$HW_DATA_DIR"
      CreateDirectory "$HW_DATA_DIR"
      CreateDirectory "$HW_DATA_DIR\MyApp-Plugins"
      CreateDirectory "$HW_DATA_DIR\MyApp-Plugins\ComputePlugin"
      CreateDirectory "$HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin"                                       

      File /oname=$HW_DATA_DIR\MyApp-Plugins\ComputePlugin\computeplugin.xplot.dll computeplugin.xplot.dll
      File /oname=$HW_DATA_DIR\MyApp-Plugins\ComputePlugin\computeplugin.VirtualVolume.dll computeplugin.VirtualVolume.dll
             
      File /oname=$HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin\hwProxyInterface.MyApp.dll hwProxyInterface.MyApp.dll

      # MyPartnerApp workspace
      CreateDirectory "$HW_WORKSPACE_DIR"      
      
      ##All the files in Group 1 will be installed to the same location, $INSTDIR
      SetOutPath "$INSTDIR"
      ;messagebox mb_ok "MyPartnerApp Program: INSTDIR is $INSTDIR"
      
      # set environment variable for current user
      WriteRegExpandStr ${env_hkcu} HEADWAVE_ROOT_DIR $MyPartnerAppInstallDir
      # make sure windows knows about the change
      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000

      # Install Sound-MyApp python scripts
      CreateDirectory $MyPartnerAppInstallDir\python\hwtoolkits\MyCompany
      File __init__.py
      File MyAppConfig.py
      File MyAppPlugin.py
      
      CopyFiles $INSTDIR\*.py $MyPartnerAppInstallDir\python\hwtoolkits\MyCompany

      # Give instructions on how to setup MyPartnerApp preferences
      ; MessageBox MB_OK "In MyPartnerApp, set File/User preferences:$\n$\nOutput directory = $HW_DATA_DIR$\n$\nCompute plugin directories = $HW_DATA_DIR\MyApp-Plugins\ComputePlugin$\n$\nExtension plugin directories = $HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin"

      # Ask use to check port
      ; MessageBox MB_OK "The MyApp to MyPartnerApp connector uses network port 2004 by default. If this is a conflict on your system you can specify a new port by editing both the config.dat and MyAppConfig.py files with a new port number."
    notfoundHwData:          
    notfoundMyPartnerApp:
      
      # messagebox mb_ok SEC1
  ${Else}
    Abort
  ${EndIf}          
SectionEnd

Function hw_data_pre
  ${If} ${SectionIsSelected} ${SEC1}
    StrCpy $HW_DATA_DIR "C:\${HW_DATA}"
    StrCpy $HW_WORKSPACE_DIR "C:\${HW_WORKSPACE}"                
  ${Else}  
      Abort
  ${EndIf}  
Functionend

Function hw_data_dir
             
Functionend

Function hw_wk_pre
  ${If} ${SectionIsSelected} ${SEC1}  
    StrCpy $HW_WORKSPACE_DIR "C:\${HW_WORKSPACE}"
  ${Else}  
      Abort
  ${EndIf}  
Functionend

Function hw_wk_dir
  Call IsPROG0HwWorkspaceSelected
  Pop $R0
  
  ${If} $R0 == "1"    
    CreateDirectory "$HW_WORKSPACE_DIR"  
  ${EndIf}         
Functionend

## Sections 2
Section "MyApp" SEC2
  ${If} ${SectionIsSelected} ${SEC2}   
    ${StrContains} $0 "Pro" "$INSTDIR"
    StrCmp $0 "" notfoundMyApp
    StrCpy $MyAppInstallDir "$INSTDIR"
    Goto doneMyApp

  doneMyApp:          
      
  ##All the files in Group 2 will be installed to the same location, $INSTDIR
  SetOutPath "$INSTDIR"
  
  !insertmacro WriteSignedUninstaller "$InstDir\Uninst.exe"

  # specify files to go in output path
  File MyApp.exe
  File readme.txt  
  File ReleaseNotes.txt        

  # Create config.dat based on user`s previous selection
  IfFileExists "$INSTDIR\config.dat" file_found file_not_found
  file_found:
    ; Do nothing
    goto end_of_test ;<== important for not continuing on the else branch
  file_not_found:
    nsExec::ExecToStack 'cmd /c "@echo ServerPort = 2003 > config.dat"'
    Pop $0 # return value/error/timeout
    Pop $1 # printed text, up to ${NSIS_MAX_STRLEN}
    DetailPrint 'cmd /c "@echo ServerPort = 2003 > config.dat" printed: $1'
    DetailPrint ""
    DetailPrint "       Return value: $0"
    DetailPrint ""
    nsExec::ExecToStack 'cmd /c "@echo MyPartnerAppPort = 2004 >> config.dat"'
    nsExec::ExecToStack 'cmd /c "@echo MyPartnerAppOutputDirectory = $HW_DATA_DIR >> config.dat"'
    nsExec::ExecToStack 'cmd /c "@echo MyPartnerAppWorkspaceDirectory = $HW_WORKSPACE_DIR >> config.dat"'
  end_of_test:

  # 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\${COMPANY_NAME}" 'Contact' "https://www.mycompany.com/contact"
  WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'Company Name' "${COMPANY_NAME}"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'DisplayName' "${PRODUCT_NAME}"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'DisplayVersion' "${PRODUCT_VERSION}"
  WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'AppID' "{e2248c93-74ae-4336-9191-1b97a3a17e7e}"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'HelpLink' "http://www.myapp.com/MyApp/HelpDocs/index.htm"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'URLInfoAbout' "https://www.mycompany.com/myapp"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'InstallLocation' "$MyAppInstallDir"    
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'Publisher' "${COMPANY_NAME}"
 
  # 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" "{e2248c93-74ae-4336-9191-1b97a3a17e7e}"                                 
  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\Uninst.exe$\"" 

  # MyLicenseApp libs 
  Delete $INSTDIR\SMyApp.exe
  Delete $INSTDIR\MyLicenseApp.log
  Delete $INSTDIR\installs.exe

  ; MessageBox MB_OK "SEC2 #3 INSTDIR is $INSTDIR"  
  StrCmp "$INSTDIR" "$PROGRAMFILES64\${PRODUCT_NAME}" 0 jump_to_if_not_equal
    goto end
  jump_to_if_not_equal:
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\config.dat
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\MyApp.exe
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\readme.txt
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\ReleaseNotes.txt
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\Uninst.exe
    RMDir $PROGRAMFILES64\${PRODUCT_NAME}
  end:
  notfoundMyApp:

  # messagebox mb_ok SEC2
  ${Else}
    Abort      
  ${EndIf}              
SectionEnd

## Section 3
Section /o "MyLicenseApp" SEC3
    ${StrContains} $0 "Pro" "$INSTDIR"
    StrCmp $0 "" notfoundMyApp
      StrCpy $MyAppInstallDir "$INSTDIR"
      Goto doneMyApp
    notfoundMyApp:

    ${StrContains} $0 "LicenseManager" "$INSTDIR"
    StrCmp $0 "" notfoundLicenseManager
      StrCpy $LicenseManagerLmInstallDir "$INSTDIR"
      Goto doneLicenseManager
    notfoundLicenseManager:
      ;MessageBox MB_OK 'Did not find LicenseManager string'
    doneLicenseManager:   
 
  ##All the files in Group 2 will be installed to the same location, $INSTDIR
  SetOutPath "$INSTDIR"
    
    # Add application to registry 
    WriteRegStr HKCU "SOFTWARE\${LICENSE_APP}" 'DisplayName' "${LICENSE_APP}"
    WriteRegStr HKCU "SOFTWARE\${LICENSE_APP}" 'InstallLocation' "$INSTDIR"    

    # Files 
  File MyApp.exe
  File MyLicenseApp.log
  File installs.exe

    doneMyApp:    

  # messagebox mb_ok sec2
SectionEnd
 
;--------------------------------
;Descriptions

  ;Language strings
  LangString DESC_SecMyApp ${LANG_ENGLISH} "MyAppTM software is an easy-to-use suite of tools for interactively generating reservoir realizations that are jointly calibrated to all available seismic, petrophysical and production knowledge."
  LangString DESC_SecMyLicenseApp ${LANG_ENGLISH} "LicenseManagerSMyApp contains all the files necessary to implement the MyLicenseApp license server."
  LangString DESC_SecHeadWave ${LANG_ENGLISH} "MyPartnerApp removes the limitations created by seismic data size to enable full visualization, interactivity, and computation delivering value across the E&P workflow to reduce uncertainty and accelerate time to first oil."

  ;Assign language strings to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${SEC0MyPartnerApp} $(DESC_SecHeadWave)      
    !insertmacro MUI_DESCRIPTION_TEXT ${SEC2} $(DESC_SecMyApp)
    !insertmacro MUI_DESCRIPTION_TEXT ${SEC2} $(DESC_SecMyLicenseApp)
  !insertmacro MUI_FUNCTION_DESCRIPTION_END

;--------------------------------
; Please don`t modify below here unless you`re a NSIS 'wiz-kid'
 
## Create $PLUGINSDIR
Function .onInit
  InitPluginsDir

  SetOutPath $TEMP
  File /oname=spltmp.bmp "MyApp_LandingPage.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  

  ; Initialize variables
  StrCpy $MyPartnerAppInstallDir ""
FunctionEnd

Function .onInstSuccess
    Delete $INSTDIR\MyAppConfig.py
    Delete $INSTDIR\MyAppPlugin.py
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
 
## Here we are selecting first sections to install
## by unselecting all the others!
Function SelectFilesMyPartnerAppData
  ${If} ${SectionIsSelected} ${SEC1}
    ;MessageBox MB_OK "SEC2 #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 1 Sections
 # for the next InstFiles page
Push $R0
Push $R1
 
 StrCpy $R0 ${PROG1_StartIndex} # Group 1 start
 
 # 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}"
 StrCpy $INSTDIR $MyPartnerAppInstallDir
 
Pop $R1
Pop $R0
FunctionEnd 

## Here we are selecting first sections to install
## by unselecting all the others!
Function SelectFilesMyPartnerAppProg      
 # 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 1 Sections
 # for the next InstFiles page
Push $R0
Push $R1
 
 StrCpy $R0 ${PROG1_StartIndex} # Group 1 start
 
 # Don`t install prog 1?
 Call IsPROG1Selected
 Pop $R0
 StrCmp $R0 1 +4
  Pop $R1
  Pop $R0
  Abort
  
  ${If} $MyPartnerAppInstallDir == ""
    StrCpy $0 0
    EnumRegKey $1 HKCU "SOFTWARE\MyPartnerAppCompany" $0
    StrCmp $1 "" done
    IntOp $0 $0 + 1
    StrCpy $INSTDIR "$PROGRAMFILES64\$1"
    SetOutPath "$INSTDIR"            
    gotMyPartnerAppDir IDNO browseMyPartnerAppDir
    StrCpy $MyPartnerAppInstallDir $PROGRAMFILES64\$1
    done: 

    StrCpy $INSTDIR $MyPartnerAppInstallDir
    SetOutPath $INSTDIR
  ${Else}  
      Abort
  ${EndIf}

 # Set current $INSTDIR to PROG1_InstDir define
 ;StrCpy $INSTDIR "${PROG1_InstDir}"
 StrCpy $INSTDIR $MyPartnerAppInstallDir
 
Pop $R1
Pop $R0
FunctionEnd 

Function SelectFilesMyApp
  ${If} ${SectionIsSelected} ${SEC2}
    ;MessageBox MB_OK "SEC2 #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 ${PROG3_StartIndex} # Group 2 start
 
 # Don`t install prog 1?
 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
 
Function SelectFilesMyLicenseApp  
Push $R0
Push $R1
 
 StrCpy $R0 ${PROG2_StartIndex}    # Group 2 start
     
 # Don't install prog 2?
 Call IsPROG3Selected
 Pop $R3
 StrCmp $R3 1 +4
  Pop $R3
  Pop $R4
  Abort
 
 # Set current $INSTDIR to PROG3_InstDir define
 StrCpy $INSTDIR "${PROG3_InstDir}"
 
Pop $R3
Pop $R4
FunctionEnd
 
## Also if no sections are selected, warn the user!
Function ComponentsLeave
Push $R0
Push $R1
Push $R2
Push $R3
Push $R4
 
 Call IsPROG0HwDataSelected
  Pop $R0 
 Call IsPROG0HwWorkspaceSelected
  Pop $R1
 Call IsPROG1Selected
  Pop $R2
 Call IsPROG2Selected
  Pop $R3  
 Call IsPROG3Selected
  Pop $R4
 StrCmp $R0 1 End
 StrCmp $R1 1 End
 StrCmp $R2 1 End
 StrCmp $R3 1 End
 StrCmp $R4 1 End
  Pop $R4 
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
 MessageBox MB_OK|MB_ICONEXCLAMATION "$(NoSectionsSelected)"
 Abort
 
End:
Pop $R1
Pop $R0
FunctionEnd
 
Function IsPROG0HwDataSelected
Push $R0
 
 StrCpy $R0 ${PROG0_HW_Data_StartIndex} # Group 0 HW Data 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 IsPROG0HwWorkspaceSelected
Push $R1
 
 StrCpy $R1 ${PROG0_HW_Wk_StartIndex} # Group 0 HW Workspace start
 
   SectionGetFlags 0 $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    
   
Function IsPROG1Selected
Push $R2
 
 StrCpy $R2 ${PROG1_StartIndex} # Group MyPartnerApp Program start
 
   SectionGetFlags 0 $R2            # Get section flags
    IntOp $R2 $R2 & ${SF_SELECTED}
    StrCmp $R2 ${SF_SELECTED} 0 +3      # If section is selected, done
     StrCpy $R2 1
 
Exch $R2
FunctionEnd   
   
Function IsPROG2Selected
Push $R3
 
 StrCpy $R3 ${PROG2_StartIndex} # Group MyApp start
 
   SectionGetFlags 0 $R3            # Get section flags
    IntOp $R3 $R3 & ${SF_SELECTED}
    StrCmp $R3 ${SF_SELECTED} 0 +3      # If section is selected, done
     StrCpy $R3 1
 
Exch $R3
FunctionEnd
 
Function IsPROG3Selected
Push $R4
 
 StrCpy $R4 ${PROG3_StartIndex}    # Group MyLicenseApp start
 
   IntOp $R4 $R4 + 1
   SectionGetFlags 1 $R2            # Get section flags
    IntOp $R4 $R4 & ${SF_SELECTED}
    StrCmp $R4 ${SF_SELECTED} 0 +3      # If section is selected, done
     StrCpy $R4 1
 
Exch $R4
FunctionEnd

## This will set all sections to how they were on the components page
## originally
Function ResetFiles
Push $R0
Push $R1
 
 StrCpy $R0 ${PROG3_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 ${PROG3_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"
 Delete $INSTDIR\MyApp_LandingPage.bmp
FunctionEnd

!else
# Uninstaller:
##############
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro DeclareLanguages

!verbose push 2
SilentInstall Silent
Section
WriteUninstaller "${GENRATINGUNINST}"
Quit
SectionEnd
!verbose pop

Section -Uninstall
  # now delete installed files and registry keys for MyApp
  ReadRegStr $0 HKCU "SOFTWARE\${COMPANY_NAME}" "InstallLocation"
  ;StrCpy $MyAppInstallDir $0 
  Delete $0\config.dat
  Delete $0\MyApp.exe
  Delete $0\readme.txt
  Delete $0\ReleaseNotes.txt
  Delete $0\MyApp_LandingPage.bmp
  Delete $0\MyAppLicense.txt
  Delete "$SMPROGRAMS\MyApp.lnk"
  DeleteRegKey HKCU "SOFTWARE\${COMPANY_NAME}"
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
  DeleteRegKey /ifempty HKCU "Software\Modern UI Test" 

  # Delete SW libs
  Delete $0\libzmq-mt-4_3_0.dll
  Delete $0\partnercompany.dll
  Delete $0\vcruntime140_1.dll       

  # Final cleanup 
  Delete "$InstDir\Uninst.exe"
  RMDir "$InstDir"
SectionEnd

!endif

有没有人有什么建议?TIA。

标签: nsis

解决方案


这就是我最终使用的:

!include "LogicLib.nsh"

;Include Modern UI
!include "MUI2.nsh"
!include "nsDialogs.nsh"
!include "nsDialogs_createTextMultiline.nsh"
!include "StrRep.nsh"
!include "ReplaceInFile.nsh"
!include "Sections.nsh"
!include "winmessages.nsh"

!define MAJOR_VERSION "1" 
!define MINOR_VERSION "2" 
!define PATCH_VERSION "3" 
!define BUILD_VERSION "4" 
    
!define APP_COPYRIGHT "MyApp © My Company 2021"
!define COMPANY_NAME "MyCompany"
!define LICENSE_APP "MyLicenseApp"        
!define FLEX_DIR "LicenseManagerSMyApp"     
!define HW_DATA "HW-Data"
!define HW_WORKSPACE "HW-Workspaces"        
!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 "${COMPANY_NAME}"

OutFile ${SETUP_NAME}
Icon "favicon.ico"
UninstallIcon "favicon.ico"
!define MUI_ICON "favicon.ico"
!define MUI_UNICON "favicon.ico"
Name "${PRODUCT_NAME}"
    
InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}\"
InstallDirRegKey HKLM "Software\$PRODUCT_NAME" ""
ShowInstDetails hide
ShowUnInstDetails hide

SetCompressor /SOLID lzma
SetCompressorDictSize 12

;Request application privileges for Windows 
RequestExecutionLevel admin

; HKLM (all users) vs HKCU (current user) defines
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!define env_hkcu 'HKCU "Environment"'

!macro WriteSignedUninstaller Destination
!makensis '"/DGENRATINGUNINST=$%TEMP%\Uninst.exe" "${__FILE__}" "/XOutfile `$%TEMP%\tempinstaller.exe`"' = 0 ; Create fake installer
!system 'set __COMPAT_LAYER=RunAsInvoker&"$%TEMP%\tempinstaller.exe"' = 2 ; Run fake installer to generate the uninstaller
!system 'SIGNTOOL sign /f ../CodeSigningCertificate/MyCompanySolutions.pfx /p MyCertPassword /tr http://timestamp.digicert.com /td SHA256 "$%TEMP%\Uninst.exe"' = 0 ; Change this line. As a demonstration, use !system 'echo Dummy >> "$%TEMP%\Uninst.exe"'
File "/oname=${Destination}" "$%TEMP%\Uninst.exe"
!macroend

!macro DeclareLanguages
!insertmacro MUI_LANGUAGE ${LANG_ENGLSH}
!macroend

!ifndef GENRATINGUNINST
Var MyPartnerAppInstallDir
Var MyAppInstallDir
Var LicenseManagerLmInstallDir

# Installer:
############
!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 MyPartnerApp Data Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_HW)"
!define MUI_PAGE_HEADER_TEXT "Choose MyPartnerApp Data directory"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder which MyPartnerApp can use as a data storage."

;Directory for MyPartnerApp files and where config.dat will point to
Var HW_DATA_DIR
Var HW_WORKSPACE_DIR

; HW Data 
!define MUI_PAGE_CUSTOMFUNCTION_PRE hw_data_pre
!define MUI_PAGE_CUSTOMFUNCTION_SHOW hw_data_dir
!define MUI_DIRECTORYPAGE_VARIABLE $HW_DATA_DIR
!insertmacro MUI_PAGE_DIRECTORY

## This is the title on the MyPartnerApp Workspace Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_HW_WK)"
!define MUI_PAGE_HEADER_TEXT "Choose MyPartnerApp Workspace directory"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder which MyPartnerApp can use as a workspace."

# HW Workspaces
!define MUI_PAGE_CUSTOMFUNCTION_PRE hw_wk_pre
!define MUI_PAGE_CUSTOMFUNCTION_SHOW hw_wk_dir 
!define MUI_DIRECTORYPAGE_VARIABLE $HW_WORKSPACE_DIR
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES    
 
## This is the title on the MyPartnerApp installation Directory page to obtain directory for %HEADWAVE_ROOT_DIR
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_HW_INST)"
!define MUI_PAGE_HEADER_TEXT "Choose MyPartnerApp Plugin installation directory"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder where MyPartnerApp is presently installed to set environment variable."
 
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesMyPartnerAppProg
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES

## This is the title on the MyApp Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_A)"
!define MUI_PAGE_HEADER_TEXT "Choose Install Location"
!define MUI_PAGE_HEADER_SUBTEXT "Select the folder in which to install MyApp."
 
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesMyApp
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES

## This is the title on the MyLicenseApp Directory page
!define MUI_DIRECTORYPAGE_TEXT_TOP "$(MUI_DIRECTORYPAGE_TEXT_TOP_B)"
!define MUI_PAGE_HEADER_TEXT "Choose Install Location"
!define MUI_PAGE_HEADER_SUBTEXT "Please choose the folder in which to install MyLicenseApp."
 
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectFilesMyLicenseApp
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
 
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE DeleteSectionsINI
!define MUI_FINISHPAGE_TEXT "In MyPartnerApp, select File/User preferences:$\n$\nOutput directory = $HW_DATA_DIR$\n$\nCompute plugin directories = $HW_DATA_DIR\MyApp-Plugins\ComputePlugin$\n$\nExtension plugin directories = $HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin$\n$\nThe MyApp to MyPartnerApp connector uses network port 8080 by default. If this is a conflict on your system you can specify a new port by editing both the config.dat and MyAppConfig.py files with a new port number."
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

;--------------------------------

LangString NoSectionsSelected ${LANG_ENGLSH} "You haven't selected any sections!"

LangString MUI_DIRECTORYPAGE_TEXT_TOP_HW ${LANG_ENGLSH} "Select \
${HW_DATA} installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_HW_WK ${LANG_ENGLSH} "Select \
${HW_WORKSPACE} installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_HW_INST ${LANG_ENGLSH} "Select \
MyPartnerApp installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_A ${LANG_ENGLSH} "Select \
${PRODUCT_NAME} installation location..."
LangString MUI_DIRECTORYPAGE_TEXT_TOP_B ${LANG_ENGLSH} "Select \
${LICENSE_APP} installation location..."

;--------------------------------
; Settings
 
!define PROG1_InstDir    "$PROGRAMFILES64"
!define PROG1_StartIndex ${SEC1}
!define PROG1_EndIndex   ${SEC1}
 
!define PROG2_InstDir    "$PROGRAMFILES64\${PRODUCT_NAME}"
!define PROG2_StartIndex ${SEC2}
!define PROG2_EndIndex   ${SEC2}
 
!define PROG3_InstDir "C:\${FLEX_DIR}"
!define PROG3_StartIndex ${SEC3}
!define PROG3_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 1
Section "MyPartnerApp Plugin" SEC1
  ${If} ${SectionIsSelected} ${SEC1}    
    ${StrContains} $0 "MyPartnerApp" "$INSTDIR" 
    StrCmp $0 "" notfoundMyPartnerApp
    Goto doneMyPartnerApp
    doneMyPartnerApp:
      SetOutPath "$HW_DATA_DIR"
      ${StrContains} $0 "Data" "$HW_DATA_DIR"
      StrCmp $0 "" notfoundHwData
      Goto doneHwData
      ;MessageBox MB_OK 'Did not find MyApp string'
    doneHwData: 
    
      ##All the files in Group 0 will be installed to the same location, $HW_DATA_DIR
      SetOutPath "$HW_DATA_DIR"
      CreateDirectory "$HW_DATA_DIR"
      CreateDirectory "$HW_DATA_DIR\MyApp-Plugins"
      CreateDirectory "$HW_DATA_DIR\MyApp-Plugins\ComputePlugin"
      CreateDirectory "$HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin"                                       

      File /oname=$HW_DATA_DIR\MyApp-Plugins\ComputePlugin\computeplugin.xplot.dll computeplugin.xplot.dll
      File /oname=$HW_DATA_DIR\MyApp-Plugins\ComputePlugin\computeplugin.VirtualVolume.dll computeplugin.VirtualVolume.dll
             
      File /oname=$HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin\hwProxyInterface.MyApp.dll hwProxyInterface.MyApp.dll

      # MyPartnerApp workspace
      CreateDirectory "$HW_WORKSPACE_DIR"      
      
      ##All the files in Group 1 will be installed to the same location, $INSTDIR
      SetOutPath "$INSTDIR"
      ;messagebox mb_ok "MyPartnerApp Program: INSTDIR is $INSTDIR"
      
      # set environment variable for current user
      WriteRegExpandStr ${env_hkcu} HEADWAVE_ROOT_DIR $INSTDIR
      # save the selected headwave program directory
      StrCpy $MyPartnerAppSelectedInstallDir $INSTDIR
      # make sure windows knows about the change
      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000

      # Install Sound-MyApp python scripts
      CreateDirectory $INSTDIR\python\hwtoolkits\MyCompany
      File __init__.py
      File MyAppConfig.py
      File MyAppPlugin.py
      
      CopyFiles $INSTDIR\*.py $INSTDIR\python\hwtoolkits\MyCompany

    notfoundHwData:          
    notfoundMyPartnerApp:
      ; Do nothing
  ${Else}
    Abort
  ${EndIf}          
SectionEnd

Function hw_data_pre
  ${If} ${SectionIsSelected} ${SEC1}
    StrCpy $HW_DATA_DIR "C:\${HW_DATA}"
    StrCpy $HW_WORKSPACE_DIR "C:\${HW_WORKSPACE}"                
  ${Else}  
      Abort
  ${EndIf}  
Functionend

Function hw_data_dir
   ; ${If} ${SectionIsSelected} ${SEC1}
   ;   SetOutPath "$INSTDIR"
   ;   CreateDirectory $HW_DATA_DIR
   ;   CreateDirectory $HW_DATA_DIR\MyApp-Plugins
   ;   CreateDirectory $HW_DATA_DIR\MyApp-Plugins\ComputePlugin
   ;   CreateDirectory $HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin                                       

   ;   File /oname=$HW_DATA_DIR\MyApp-Plugins\ComputePlugin\computeplugin.xplot.dll computeplugin.xplot.dll
   ;   File /oname=$HW_DATA_DIR\MyApp-Plugins\ComputePlugin\computeplugin.VirtualVolume.dll computeplugin.VirtualVolume.dll
             
   ;   File /oname=$HW_DATA_DIR\MyApp-Plugins\ExtensionPlugin\hwProxyInterface.MyApp.dll hwProxyInterface.MyApp.dll
   ; ${EndIf}                   
Functionend

Function hw_wk_pre
  ${If} ${SectionIsSelected} ${SEC1}  
    StrCpy $HW_WORKSPACE_DIR "C:\${HW_WORKSPACE}"
  ${Else}  
      Abort
  ${EndIf}  
Functionend

Function hw_wk_dir
  ${If} ${SectionIsSelected} ${SEC1}    
    CreateDirectory "$HW_WORKSPACE_DIR"  
  ${EndIf}         
Functionend

## Sections 2
Section "MyApp" SEC2
  ${If} ${SectionIsSelected} ${SEC2} 
    ${StrContains} $0 "Pro" "$INSTDIR"
    StrCmp $0 "" notfoundMyApp
    StrCpy $MyAppInstallDir "$INSTDIR"
    Goto doneMyApp
      ;MessageBox MB_OK 'Did not find MyApp string'

  doneMyApp:          
      
  ##All the files in Group 2 will be installed to the same location, $INSTDIR
  SetOutPath "$INSTDIR"
  
  !insertmacro WriteSignedUninstaller "$InstDir\Uninst.exe"

  # specify files to go in output path
  File MyApp.exe
  File readme.txt  
  File ReleaseNotes.txt        

  # Create config.dat based on user`s previous selection
  IfFileExists "$INSTDIR\config.dat" file_found file_not_found
  file_found:
    ; Do nothing
    goto end_of_test ;<== important for not continuing on the else branch
  file_not_found:
    nsExec::ExecToStack 'cmd /c "@echo ServerPort = 2003 > config.dat"'
    Pop $0 # return value/error/timeout
    Pop $1 # printed text, up to ${NSIS_MAX_STRLEN}
    DetailPrint 'cmd /c "@echo ServerPort = 2003 > config.dat" printed: $1'
    DetailPrint ""
    DetailPrint "       Return value: $0"
    DetailPrint ""
    nsExec::ExecToStack 'cmd /c "@echo MyPartnerAppPort = 2004 >> config.dat"'
    nsExec::ExecToStack 'cmd /c "@echo MyPartnerAppOutputDirectory = $HW_DATA_DIR >> config.dat"'
    
    # 2     
    ; messagebox mb_ok "MyApp Main: HW Data Dir $HW_DATA_DIR"
    nsExec::ExecToStack 'cmd /c "@echo MyPartnerAppWorkspaceDirectory = $HW_WORKSPACE_DIR >> config.dat"'
    
    # 3 
    ; messagebox mb_ok "MyApp Main: HW Workspace Dir $HW_WORKSPACE_DIR"
  end_of_test:

  # 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\${COMPANY_NAME}" 'Contact' "https://www.mycompany.com/contact"
  WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'Company Name' "${COMPANY_NAME}"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'DisplayName' "${PRODUCT_NAME}"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'DisplayVersion' "${PRODUCT_VERSION}"
  WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'AppID' "{e2248c93-74ae-4336-9191-1b97a3a17e7e}"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'HelpLink' "http://www.myapp.com/MyApp/HelpDocs/index.htm"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'URLInfoAbout' "https://www.mycompany.com/myapp"
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'InstallLocation' "$MyAppInstallDir"    
    WriteRegStr HKCU "SOFTWARE\${COMPANY_NAME}" 'Publisher' "${COMPANY_NAME}"
 
  # 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" "{e2248c93-74ae-4336-9191-1b97a3a17e7e}"                                 
  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\Uninst.exe$\"" 

  # MyLicenseApp libs 
  Delete $INSTDIR\SMyApp.exe
  Delete $INSTDIR\MyLicenseApp.log
  Delete $INSTDIR\installs.exe

  ; MessageBox MB_OK "SEC2 #3 INSTDIR is $INSTDIR"  
  StrCmp "$INSTDIR" "$PROGRAMFILES64\${PRODUCT_NAME}" 0 jump_to_if_not_equal
    goto end
  jump_to_if_not_equal:
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\config.dat
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\MyApp.exe
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\readme.txt
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\ReleaseNotes.txt
    Delete $PROGRAMFILES64\${PRODUCT_NAME}\Uninst.exe
    RMDir $PROGRAMFILES64\${PRODUCT_NAME}
  end:
  notfoundMyApp:

  # messagebox mb_ok SEC2
  ${Else}
    Abort      
  ${EndIf}              
SectionEnd

## Section 3
Section /o "MyLicenseApp" SEC3
    ${StrContains} $0 "Pro" "$INSTDIR"
    StrCmp $0 "" notfoundMyApp
      StrCpy $MyAppInstallDir "$INSTDIR"
      Goto doneMyApp
    notfoundMyApp:
      ;MessageBox MB_OK 'Did not find MyApp string'

    ${StrContains} $0 "LicenseManager" "$INSTDIR"
    StrCmp $0 "" notfoundLicenseManager
      StrCpy $LicenseManagerLmInstallDir "$INSTDIR"
      Goto doneLicenseManager
    notfoundLicenseManager:
      ; Do nothing 
    doneLicenseManager:   
 
  ##All the files in Group 2 will be installed to the same location, $INSTDIR
  SetOutPath "$INSTDIR"
    
    # Add application to registry 
    WriteRegStr HKCU "SOFTWARE\${LICENSE_APP}" 'DisplayName' "${LICENSE_APP}"
    WriteRegStr HKCU "SOFTWARE\${LICENSE_APP}" 'InstallLocation' "$INSTDIR"    

    # Files 
  File MyApp.exe
  File MyLicenseApp.log
  File installs.exe

    doneMyApp:    

SectionEnd
 
;--------------------------------
;Descriptions

  ;Language strings
  LangString DESC_SecMyApp ${LANG_ENGLISH} "MyAppTM software is an easy-to-use suite of tools for interactively generating reservoir realizations that are jointly calibrated to all available seismic, petrophysical and production knowledge."
  LangString DESC_SecMyLicenseApp ${LANG_ENGLISH} "LicenseManagerSMyApp contains all the files necessary to implement the MyLicenseApp license server."
  LangString DESC_SecHeadWave ${LANG_ENGLISH} "MyPartnerApp removes the limitations created by seismic data size to enable full visualization, interactivity, and computation delivering value across the E&P workflow to reduce uncertainty and accelerate time to first oil."

  ;Assign language strings to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${SEC0MyPartnerApp} $(DESC_SecHeadWave)      
    !insertmacro MUI_DESCRIPTION_TEXT ${SEC2} $(DESC_SecMyApp)
    !insertmacro MUI_DESCRIPTION_TEXT ${SEC2} $(DESC_SecMyLicenseApp)
  !insertmacro MUI_FUNCTION_DESCRIPTION_END

;--------------------------------
; Please don`t modify below here unless you`re a NSIS 'wiz-kid'
 
## Create $PLUGINSDIR
Function .onInit
  InitPluginsDir

  SetOutPath $TEMP
  File /oname=spltmp.bmp "MyApp_LandingPage.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  

  ; Initialize variables
  StrCpy $MyPartnerAppInstallDir ""
FunctionEnd

Function .onInstSuccess
    Delete $INSTDIR\MyAppConfig.py
    Delete $INSTDIR\MyAppPlugin.py
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
 
## Here we are selecting first sections to install
## by unselecting all the others!
Function SelectFilesMyPartnerAppData
  ${If} ${SectionIsSelected} ${SEC1}
    ;MessageBox MB_OK "SEC2 #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 1 Sections
 # for the next InstFiles page
Push $R0
Push $R1
 
 StrCpy $R0 ${PROG1_StartIndex} # Group 1 start

 

 
 # Don`t install prog 1?
 Call IsPROG1Selected
 Pop $R0
 StrCmp $R0 1 +4
  Pop $R1
  Pop $R0
  Abort

  ${If} $MyPartnerAppInstallDir == ""
    StrCpy $0 0
    loop:
      EnumRegKey $1 HKCU "SOFTWARE\MyPartnerAppCompany" $0
      StrCmp $1 "" done
      IntOp $0 $0 + 1
      StrCpy $INSTDIR "$PROGRAMFILES64\$1"
      SetOutPath "$INSTDIR"            
      StrCpy $MyPartnerAppInstallDir $PROGRAMFILES64\$1
      Goto loop
    done: 
    ; messagebox mb_ok "MyPartnerAppInstallDir is $MyPartnerAppInstallDir"

    StrCpy $INSTDIR $MyPartnerAppInstallDir
    SetOutPath $INSTDIR
  ${Else}  
      Abort
  ${EndIf}

 # Set current $INSTDIR to PROG1_InstDir define
 StrCpy $INSTDIR $MyPartnerAppInstallDir
 
Pop $R1
Pop $R0
FunctionEnd 

Function SelectFilesMyApp
  ${If} ${SectionIsSelected} ${SEC2}
    StrCpy $INSTDIR "${PROG2_InstDir}"
  ${Else}  
      Abort
  ${EndIf}  
 
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 SelectFilesMyLicenseApp
  ${If} ${SectionIsSelected} ${SEC3}
    StrCpy $INSTDIR "${PROG3_InstDir}"
  ${Else}  
      Abort
  ${EndIf} 

FunctionEnd
 
## Also if no sections are selected, warn the user!
Function ComponentsLeave
Push $R0
Push $R1
Push $R2
 
 Call IsPROG1Selected
  Pop $R0
 Call IsPROG2Selected
  Pop $R1  
 Call IsPROG3Selected
  Pop $R2
 StrCmp $R0 1 End
 StrCmp $R1 1 End
 StrCmp $R2 1 End
  Pop $R2
  Pop $R1
  Pop $R0
 MessageBox MB_OK|MB_ICONEXCLAMATION "$(NoSectionsSelected)"
 Abort
 
End:
Pop $R1
Pop $R0
FunctionEnd
 
Function IsPROG0HwDataSelected
Push $R0
 
 StrCpy $R0 ${PROG0_HW_Data_StartIndex} # Group 0 HW Data 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 $R3
 
 StrCpy $R3 ${PROG2_StartIndex} # Group MyApp start
 
   SectionGetFlags 0 $R3            # Get section flags
    IntOp $R3 $R3 & ${SF_SELECTED}
    StrCmp $R3 ${SF_SELECTED} 0 +3      # If section is selected, done
     StrCpy $R3 1
 
Exch $R3
FunctionEnd
 
Function IsPROG3Selected
Push $R4
 
 StrCpy $R4 ${PROG3_StartIndex}    # Group MyLicenseApp start
 
   IntOp $R4 $R4 + 1
   SectionGetFlags 1 $R2            # Get section flags
    IntOp $R4 $R4 & ${SF_SELECTED}
    StrCmp $R4 ${SF_SELECTED} 0 +3      # If section is selected, done
     StrCpy $R4 1
 
Exch $R4
FunctionEnd

## This will set all sections to how they were on the components page
## originally
Function ResetFiles
Push $R0
Push $R1
 
 StrCpy $R0 ${PROG3_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 ${PROG3_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"
 Delete $INSTDIR\MyApp_LandingPage.bmp
FunctionEnd

!else
# Uninstaller:
##############
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro DeclareLanguages

!verbose push 2
SilentInstall Silent
Section
WriteUninstaller "${GENRATINGUNINST}"
Quit
SectionEnd
!verbose pop

Section -Uninstall
  # now delete installed files and registry keys for MyApp
  ReadRegStr $0 HKCU "SOFTWARE\${COMPANY_NAME}" "InstallLocation"
  Delete $0\config.dat
  Delete $0\MyApp.exe
  Delete $0\readme.txt
  Delete $0\ReleaseNotes.txt
  Delete $0\MyApp_LandingPage.bmp
  Delete $0\MyAppLicense.txt
  Delete "$SMPROGRAMS\MyApp.lnk"
  DeleteRegKey HKCU "SOFTWARE\${COMPANY_NAME}"
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
  DeleteRegKey /ifempty HKCU "Software\Modern UI Test" 

  # Delete Seisware libs
  Delete $0\libzmq-mt-4_3_0.dll
  Delete $0\partnercompany.dll
  Delete $0\vcruntime140_1.dll       

  # Final cleanup 
  Delete "$InstDir\Uninst.exe"
  ;RMDir $1
  RMDir "$InstDir"
SectionEnd

!endif

推荐阅读