Search code examples
installationnsis

NSIS Install like in TeamViewer (Portable mode option)


What I basically want is TeamViewer-like first page for my NSIS installer with the following options:

  1. 3 radio buttons for: Run Only; Install for current user; Install for all users (requires restart with admin rights).
  2. A label for license like in TeamViewer (i.e. no actual EULA page, only a link to it in the footer).
  3. A button that can change text, i.e. Accept and Run or Accept and Install.

I cannot figure out how to do it easily in terms of UI and in terms of control flow.

Also I need the ability to restart the installer if user decides to install program for all users (i.e. I guess there should be a detectable command line switch, so that if present installer will automatically assume 3rd install type).

A screenshot of a sample UI as requested:

enter image description here

A sample NSIS template would be greatly appreciated.

Thanks.


Solution

  • ...
    RequestExecutionLevel user
    
    !include LogicLib.nsh
    !include nsDialogs.nsh
    !include FileFunc.nsh
    !include MUI2.nsh
    
    Var mode
    Var modeRadioRun
    Var modeRadioInstCU
    Var modeRadioInstLM
    
    Function OnRadioChange
    GetDlgItem $1 $hwndparent 1 ; Find Install/Next button
    ${NSD_GetState} $modeRadioRun $0
    ${If} $0 = ${BST_CHECKED} 
        ${NSD_SetText} $1 "Accept && Run" 
    ${Else}
        ${NSD_SetText} $1 "Accept && Install" 
    ${EndIf}
    FunctionEnd
    
    Function ModePageCreate
    !insertmacro MUI_HEADER_TEXT "Welcome to blah" "blah blah"
    
    ${GetParameters} $0
    ClearErrors
    ${GetOptions} "$0" "/ELEVATEDINSTALL" $0
    ${IfNot} ${Errors}
        UserInfo::GetAccountType
        Pop $0
        ${If} $0 == "Admin"
            StrCpy $mode 1
            Abort ; Skip page and start installing
        ${Else}
            MessageBox mb_iconstop "Admin rights required!"
        ${EndIf}
    ${EndIf}
    
    nsDialogs::Create 1018
    Pop $0
    
    ${NSD_CreateRadioButton} 30u 20u 50% 12u "Run"
    Pop $modeRadioRun
    ${NSD_OnClick} $modeRadioRun OnRadioChange
    
    ${NSD_CreateRadioButton} 30u 40u 50% 12u "Install for current user"
    Pop $modeRadioInstCU
    ${NSD_OnClick} $modeRadioInstCU OnRadioChange
    
    ${NSD_CreateRadioButton} 30u 60u 50% 12u "Install for all users"
    Pop $modeRadioInstLM
    ${NSD_OnClick} $modeRadioInstLM OnRadioChange
    
    ${NSD_CreateLink} 20u -14u 50% 12u "License"
    Pop $0
    ${NSD_OnClick} $0 ShowLicense
    
    ${NSD_Check} $modeRadioRun
    call OnRadioChange ; Trigger button change
    nsDialogs::Show
    FunctionEnd
    
    Function ModePageLeave
    ${NSD_GetState} $modeRadioRun $0
    ${NSD_GetState} $modeRadioInstCU $1
    ${If} $0 = ${BST_CHECKED}
        InitPluginsDir
        SetOutPath $pluginsdir
        File "myapp.exe"
        ExecWait '"$pluginsdir\myapp.exe"'
        SetOutPath $temp ; Don't lock $pluginsdir
        Quit
    ${ElseIf} $1 = ${BST_CHECKED}
        StrCpy $mode 0
    ${Else}
        StrCpy $mode 1
        UserInfo::GetAccountType
        Pop $0
        ${If} $0 != "Admin"
            ExecShell "runas" '"$exepath"' "/ELEVATEDINSTALL"
            Quit
        ${EndIf}
    ${EndIf}
    FunctionEnd
    
    Function ShowLicense
    ExecShell "" "http://example.com/license"
    FunctionEnd
    
    Page Custom ModePageCreate ModePageLeave
    !insertmacro MUI_PAGE_INSTFILES
    !insertmacro MUI_UNPAGE_CONFIRM
    !insertmacro MUI_UNPAGE_INSTFILES
    !insertmacro MUI_LANGUAGE "English"
    
    Section
    ${If} $mode > 0
        SetShellVarContext all
        StrCpy $InstDir "$ProgramFiles\MyApp"
    ${Else}
        SetShellVarContext current
        StrCpy $InstDir "$LocalAppData\Programs\MyApp"
    ${EndIf}
    
    SetOutPath $InstDir
    File myapp.exe
    CreateShortcut "$SMPrograms\MyApp.lnk" "$InstDir\myapp.exe"
    WriteUninstaller "$InstDir\Uninst.exe"
    WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyAppGuid" "UninstallString" '"$InstDir\Uninst.exe"'
    WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyAppGuid" "DisplayName" "MyApp blah blah"
    SectionEnd
    
    Section Uninstall
    ; Todo: Remove files and registry entries (You should write to a .ini in $InstDir so you know if it was a per user or machine install)
    RMDir "$InstDir"
    SectionEnd
    

    You might want to edit the base UI to make the install button larger with Resource Hacker (on one of the files in NSIS\Contrib\UIs) and in the script use ChangeUI to apply.