简体   繁体   中英

Can I get NSIS to make a single installer that handles local deployment and system deployment?

Chrome has an installer that can be used to install system wide, or to a user's home directory if they are not an administrator. This is useful for when you're deploying in a corporate environment where you still want to allow your potential users to install even when they don't necessarily have permission to.

Can NSIS be used to create such an installer?

Turns out it can. The important parts are:

  • RequestExecutionLevel highest : This ensures that the installer gets the highest privilege available to the user's account. ie if they are in the Administrator group, the installer will ask for privilege escalation.
  • Determining if the user is an Administrator or not. This is achieved using the UserInfo plugin. It's straightforward enough.
  • SetShellVarContext all|current : This determines the value of special registry root key SHCTX . With all , it means the same as HKLM (system wide), for current it results in HKCU . SetShellVarContext also affects whether or not the value of $SMPROGRAMS refers to the system wide start menu or the just user's hierachy.

Here's a skeleton for an installer that can deploy system wide or locally, depending on the user account's permissions. It uses C:\\Windows\\write.exe as its payload, and optionally installs start menu items and a desktop shortcut. It also puts a reference to the uninstaller in the registry such that it shows up in the Add/Remove Programs dialog. I used NSIS 3.0 (beta) to build this, but I don't see any obvious reason why it wouldn't work with a recent 2.x.

!include "MUI2.nsh"

!define PRODUCT_NAME "DummyProduct"
!define VERSION "0.0.1"

Var INSTDIR_BASE

Name "${PRODUCT_NAME}"
OutFile "${PRODUCT_NAME} Installer.exe"

InstallDir ""

; Take the highest execution level available
; This means that if it's possible to, we become an administrator
RequestExecutionLevel highest

!macro ONINIT un
    Function ${un}.onInit
        ; The value of SetShellVarContext detetmines whether SHCTX is HKLM or HKCU
        ; and whether SMPROGRAMS refers to all users or just the current user
        UserInfo::GetAccountType
        Pop $0
        ${If} $0 == "Admin"
            ; If we're an admin, default to installing to C:\Program Files
            SetShellVarContext all
            StrCpy $INSTDIR_BASE "$PROGRAMFILES64"
        ${Else}
            ; If we're just a user, default to installing to ~\AppData\Local
            SetShellVarContext current
            StrCpy $INSTDIR_BASE "$LOCALAPPDATA"
        ${EndIf}

        ${If} $INSTDIR == ""
            ; This only happens in the installer, because the uninstaller already knows INSTDIR
            ReadRegStr $0 SHCTX "Software\${PRODUCT_NAME}" ""

            ${If} $0 != ""
                ; If we're already installed, use the existing directory
                StrCpy $INSTDIR "$0"
            ${Else}
                StrCpy $INSTDIR "$INSTDIR_BASE\${PRODUCT_NAME}"
            ${Endif}
        ${Endif}
    FunctionEnd
!macroend

; Define the function twice, once for the installer and again for the uninstaller
!insertmacro ONINIT ""
!insertmacro ONINIT "un"

!define MUI_ABORTWARNING

!define MUI_COMPONENTSPAGE_NODESC
!insertmacro MUI_PAGE_COMPONENTS

!insertmacro MUI_PAGE_DIRECTORY

Var STARTMENU_FOLDER
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${PRODUCT_NAME}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!insertmacro MUI_PAGE_STARTMENU ${PRODUCT_NAME} $STARTMENU_FOLDER

!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES

!insertmacro MUI_LANGUAGE "English"

Section "-Main Component"
    SetOutPath "$INSTDIR"

    File "C:\Windows\write.exe"

    WriteRegStr SHCTX "Software\${PRODUCT_NAME}" "" $INSTDIR

    ; These registry entries are necessary for the program to show up in the Add/Remove programs dialog
    WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME}"
    WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" '"$INSTDIR\Uninstall.exe"'
    WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "NoModify" 1
    WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "NoRepair" 1

    WriteUninstaller "$INSTDIR\Uninstall.exe"

    !insertmacro MUI_STARTMENU_WRITE_BEGIN ${PRODUCT_NAME}
        CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER\"
        CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${PRODUCT_NAME}.lnk" "$INSTDIR\write.exe"
    !insertmacro MUI_STARTMENU_WRITE_END
SectionEnd

Section "Desktop shortcut"
    CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\write.exe"
SectionEnd

Section "Uninstall"
    Delete "$INSTDIR\write.exe"

    Delete "$INSTDIR\Uninstall.exe"

    RMDir /r "$INSTDIR"

    !insertmacro MUI_STARTMENU_GETFOLDER ${PRODUCT_NAME} $STARTMENU_FOLDER
    Delete "$SMPROGRAMS\$STARTMENU_FOLDER\${PRODUCT_NAME}.lnk"
    RMDir /r "$SMPROGRAMS\$STARTMENU_FOLDER"

    Delete "$DESKTOP\${PRODUCT_NAME}.lnk"

    DeleteRegKey /ifempty SHCTX "Software\${PRODUCT_NAME}"

    DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
SectionEnd

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM