Ctrl K
ComunidadGuías…

windows/bleachbit.nsi

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
;  vim: ts=4:sw=4:expandtab
;
;  BleachBit
;  Copyright (C) 2008-2025 Andrew Ziem
;  https://www.bleachbit.org
;
;  This program is free software: you can redistribute it and/or modify
;  it under the terms of the GNU General Public License as published by
;  the Free Software Foundation, either version 3 of the License, or
;  (at your option) any later version.
;
;  This program is distributed in the hope that it will be useful,
;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;  GNU General Public License for more details.
;
;  You should have received a copy of the GNU General Public License
;  along with this program.  If not, see <https://www.gnu.org/licenses/>.

;  @scriptversion v3.0.1.1429
;  @scriptdate 2019-12-01


;--------------------------------
;Pack header:

; Compress installer exehead with an executable compressor.

; Paths should be absolute to allow building from any location.
; Note that your executable compressor should not compress the first icon.

!ifdef packhdr
  ;Using UPX path info from windows/setup.py ->
  !ifndef UPX_EXE
    !error "packhdr is defined but UPX_EXE is not. Pass /DUPX_EXE=<path> to makensis."
  !endif
  !packhdr "$%TEMP%\exehead.tmp" '"${UPX_EXE}" -9 -q "$%TEMP%\exehead.tmp"'
!endif


;--------------------------------
;NSIS version

; Older NSIS creates the plugin directory with weak permissions (CVE-2023-37378),
; loses a race creating it (bug 1315, fixed in 3.11) or uses the Low IL temp directory
; when elevated (bug 1326, fixed in 3.12), and the inner instance runs elevated.
; The version is packed as decimal digits: 3.12 is 0x03012000.
!if ${NSIS_PACKEDVERSION} < 0x03012000
  !error "NSIS 3.12 or later is required"
!endif


;--------------------------------
;Include Modern UI

  !include "MUI2.nsh"


;--------------------------------
;General

  ;Name and file
  !define prodname "BleachBit"
  !define COMPANY_NAME "BleachBit" ; # used by NsisMultiUser
  !define PROG_AUTHOR "Andrew Ziem"
  !define PROG_COPYRIGHT "Andrew Ziem"
  BrandingText "${PROG_COPYRIGHT}"
  Name "${prodname}"
  ; ----------------------------- disable warning overwrite default language strings (wrn 6030)
  ;!pragma warning disable 6030
  ; ----------------------------- disable warning missing strings in some not english section (wrn 6040)
  ;!pragma warning disable 6040

; windows/setup.py passes UPX_TAG for UPX builds
!define /ifndef UPX_TAG ""
!ifdef NoTranslations
  OutFile "${prodname}-${VERSION}-setup-English${UPX_TAG}.exe"
!else
  OutFile "${prodname}-${VERSION}-setup${UPX_TAG}.exe"
!endif

; Unicode requires NSIS version 3 or later
Unicode true


;--------------------------------
;MultiUser defines

; https://github.com/Drizin/NsisMultiUser/wiki/Defines
!define PRODUCT_NAME "${prodname}" ; exact copy to another name for multi-user script
; !define VERSION "2.3"
; "VERSION" already defined!
!define PROGEXE "${prodname}.exe"
; !define COMPANY_NAME "BleachBit"
; "COMPANY_NAME" already defined!

; An option (MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS) defines whether simultaneous per-user
; and per-machine installations on the same machine are allowed. If set to disallow, the installer
; always requires elevation when there's per-machine installation in order to remove it first.
!define MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS 0
; Decision to don't ALLOW_BOTH_INSTALLATIONS was, because it's just to risky to have to versions
; installed at the same time and BB maybe run into unknown issues.
; This means now, that maybe a per-machine installation gets deinstalled and a per-user installation
; gets preferenced!

; An option (MULTIUSER_INSTALLMODE_ALLOW_ELEVATION) defines whether elevation if allowed.
; If elevation is disabled, the per-machine option becomes available only if the (un)installer
; is started elevated from Windows and is disabled otherwise.
!define MULTIUSER_INSTALLMODE_ALLOW_ELEVATION 1

!define MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT 0

; MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS:
; 0 or 1, (only available if MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = 1 and there are 0 or 2 installations
; on the system) when running as user and is set to 1, per-machine installation is pre-selected, otherwise
; per-user installation.
!define MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS 1

; MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER:
; 0 or 1, (only available if there are 0 or 2 installations on the system) when running as admin and
; is set to 1, per-user installation is pre-selected, otherwise per-machine installation.
!define MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER 0

!define MULTIUSER_INSTALLMODE_64_BIT 0
!define MULTIUSER_INSTALLMODE_INSTDIR "${prodname}"


;--------------------------------
;Installer-/UnInstaller-Attributes - Version Information
; https://nsis.sourceforge.io/Docs/Chapter4.html#versioninfo

;!define File_VERSION 2.3.0.0
; Later:
!define File_VERSION ${VERSION}.0

!ifdef NoTranslations
  VIAddVersionKey /LANG=1033 "ProductName"     "${prodname}"
  VIAddVersionKey /LANG=1033 "ProductVersion"  "${File_VERSION}"
  VIAddVersionKey /LANG=1033 "Comments"        ""
  VIAddVersionKey /LANG=1033 "CompanyName"     "BleachBit.org"
  VIAddVersionKey /LANG=1033 "LegalTrademarks" "${PROG_AUTHOR}"
  VIAddVersionKey /LANG=1033 "LegalCopyright"  "${PROG_COPYRIGHT}"
  VIAddVersionKey /LANG=1033 "FileVersion"     "${File_VERSION}"
  VIAddVersionKey /LANG=1033 "FileDescription" "${prodname} Setup"
!endif

!ifndef NoTranslations
  VIAddVersionKey /LANG=0    "ProductName"     "${prodname}"
  VIAddVersionKey /LANG=0    "ProductVersion"  "${File_VERSION}"
  VIAddVersionKey /LANG=0    "Comments"        ""
  VIAddVersionKey /LANG=0    "CompanyName"     "BleachBit.org"
  VIAddVersionKey /LANG=0    "LegalTrademarks" "${PROG_AUTHOR}"
  VIAddVersionKey /LANG=0    "LegalCopyright"  "${PROG_COPYRIGHT}"
  VIAddVersionKey /LANG=0    "FileVersion"     "${File_VERSION}"
  VIAddVersionKey /LANG=0    "FileDescription" "${prodname} Setup"
!endif

; VIAddVersionKey "InternalName"       ""
; VIAddVersionKey "OriginalFilename"   ""

VIProductVersion ${File_VERSION}
VIFileVersion ${File_VERSION}


;--------------------------------
  ;Default installation folder
  ; NsisMultiUser sets the directory.
  ;InstallDir "$PROGRAMFILES\${prodname}"

  ;Request application privileges for Windows Vista
  ; NsisMultiUser sets this, when needed.
  ;RequestExecutionLevel admin


;--------------------------------
;Installer-/UnInstaller-Attributes - Compiler Flags
; https://nsis.sourceforge.io/Docs/Chapter4.html#flags

; Set default compressor:
; CI already does "SetCompressor /FINAL zlib"
; Best compression: https://nsis.sourceforge.io/Docs/Chapter1.html#intro-features
!ifdef Compressor
  SetCompressor /SOLID lzma
!endif


;--------------------------------
; Rest of old part "multi-user"

!addplugindir /x86-unicode ".\NsisPluginsUnicode\"
!addincludedir ".\NsisInclude"
!include UAC.nsh
!include NsisMultiUser.nsh
!include LogicLib.nsh
!include Sections.nsh
!include StdUtils.nsh
!include WinVer.nsh

Caption "$(INSTALLER_CAPTION)"

;--------------------------------
;Interface Settings

  !define MUI_ABORTWARNING


;--------------------------------
;Language Selection Dialog Settings

  ;Remember the installer language
  !define MUI_LANGDLL_REGISTRY_ROOT "HKCU"
  !define MUI_LANGDLL_REGISTRY_KEY "Software\${prodname}"
  !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language"


;--------------------------------
;Pages

; General:
!define /IfNDef MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\orange-install-nsis.ico"
!define /IfNDef MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\orange-uninstall-nsis.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "picture.MUI2\bleachbit_150x57.bmp"
!define MUI_COMPONENTSPAGE_SMALLDESC

; Installer:
!define MUI_WELCOMEFINISHPAGE_BITMAP "picture.MUI2\bleachbit_164x314.bmp"
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomeLicensePre
!insertmacro MUI_PAGE_WELCOME
!define MUI_LICENSEPAGE_RADIOBUTTONS
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomeLicensePre
!insertmacro MUI_PAGE_LICENSE "gpl-3.0.rtf"
;Later:
;!insertmacro MUI_PAGE_LICENSE "$(MUI_LICENSE)"
;!define MUI_PAGE_CUSTOMFUNCTION_PRE "MULTIUSER_PAGE_INSTALLMODE_Pre"
;!define MUI_PAGE_CUSTOMFUNCTION_LEAVE "MULTIUSER_PAGE_INSTALLMODE_Leave"
!insertmacro MULTIUSER_PAGE_INSTALLMODE
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION RunBleachBit
;!define MUI_FINISHPAGE_LINK "Visit the ${prodname} web site."
;Later:
!define MUI_FINISHPAGE_LINK "$(BLEACHBIT_MUI_FINISHPAGE_LINK)"
!define MUI_FINISHPAGE_LINK_LOCATION "https://www.bleachbit.org"
;Later:
;!define MUI_FINISHPAGE_LINK_LOCATION "${PRODURL}"
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
!insertmacro MUI_PAGE_FINISH

; Uninstaller:
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "picture.MUI2\bleachbit_164x314.bmp"
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
;Later:
;!define MUI_PAGE_CUSTOMFUNCTION_PRE "un.MULTIUSER_UnPAGE_INSTALLMODE_Pre"
;!define MUI_PAGE_CUSTOMFUNCTION_LEAVE "un.MULTIUSER_UnPAGE_INSTALLMODE_Leave"
!insertmacro MULTIUSER_UNPAGE_INSTALLMODE
; MUI_UNPAGE_DIRECTORY not needed, ATM.
; !insertmacro MUI_UNPAGE_DIRECTORY
!insertmacro MUI_UNPAGE_COMPONENTS
!insertmacro MUI_UNPAGE_INSTFILES
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
!insertmacro MUI_UNPAGE_FINISH

; MUI_LANGUAGE[EX] should be inserted after the MUI_[UN]PAGE_* macros!


;--------------------------------
;Languages

  !insertmacro MUI_LANGUAGE "English"
!ifndef NoTranslations
  !insertmacro MUI_LANGUAGE "Albanian"
  !insertmacro MUI_LANGUAGE "Arabic"
  !insertmacro MUI_LANGUAGE "Asturian"
  !insertmacro MUI_LANGUAGE "Basque"
  !insertmacro MUI_LANGUAGE "Belarusian"
  !insertmacro MUI_LANGUAGE "Bosnian"
  !insertmacro MUI_LANGUAGE "Bulgarian"
  !insertmacro MUI_LANGUAGE "Catalan"
  !insertmacro MUI_LANGUAGE "Croatian"
  !insertmacro MUI_LANGUAGE "Czech"
  !insertmacro MUI_LANGUAGE "Danish"
  !insertmacro MUI_LANGUAGE "Dutch"
  !insertmacro MUI_LANGUAGE "Estonian"
  !insertmacro MUI_LANGUAGE "Finnish"
  !insertmacro MUI_LANGUAGE "French"
  !insertmacro MUI_LANGUAGE "Galician"
  !insertmacro MUI_LANGUAGE "German"
  !insertmacro MUI_LANGUAGE "Greek"
  !insertmacro MUI_LANGUAGE "Hebrew"
  !insertmacro MUI_LANGUAGE "Hungarian"
  !insertmacro MUI_LANGUAGE "Indonesian"
  !insertmacro MUI_LANGUAGE "Italian"
  ; Override upstream Italian.nsh: add line break on finish page (issue #1453)
  ; The last LangString wins; 6030 only warns about the replaced string
  !pragma warning push
  !pragma warning disable 6030
  LangString MUI_TEXT_FINISH_INFO_REBOOT ${LANG_ITALIAN} "Per completare l'installazione di $(^NameDA) il computer deve essere riavviato.$\r$\n$\r$\nVuoi riavviarlo ora?"
  LangString MUI_UNTEXT_FINISH_INFO_REBOOT ${LANG_ITALIAN} "Per completare la disinstallazione di $(^NameDA) il computer deve essere riavviato.$\r$\n$\r$\nVuoi riavviarlo ora?"
  !pragma warning pop
  !insertmacro MUI_LANGUAGE "Japanese"
  !insertmacro MUI_LANGUAGE "Korean"
  !insertmacro MUI_LANGUAGE "Latvian"
  !insertmacro MUI_LANGUAGE "Lithuanian"
  !insertmacro MUI_LANGUAGE "Malay"
  !insertmacro MUI_LANGUAGE "Norwegian"
  !insertmacro MUI_LANGUAGE "Polish"
  !insertmacro MUI_LANGUAGE "Portuguese"
  !insertmacro MUI_LANGUAGE "PortugueseBR"
  !insertmacro MUI_LANGUAGE "Romanian"
  !insertmacro MUI_LANGUAGE "Russian"
  !insertmacro MUI_LANGUAGE "Serbian"
  !insertmacro MUI_LANGUAGE "SimpChinese"
  !insertmacro MUI_LANGUAGE "Slovak"
  !insertmacro MUI_LANGUAGE "Slovenian"
  !insertmacro MUI_LANGUAGE "Spanish"
  !insertmacro MUI_LANGUAGE "Swedish"
  !insertmacro MUI_LANGUAGE "Thai"
  !insertmacro MUI_LANGUAGE "TradChinese"
  !insertmacro MUI_LANGUAGE "Turkish"
  !insertmacro MUI_LANGUAGE "Ukrainian"
  !insertmacro MUI_LANGUAGE "Uzbek"
  !insertmacro MUI_LANGUAGE "Vietnamese"
!endif


!include NsisMultiUserLang.nsh

!include "StrFunc.nsh"
# Declare used functions
${StrCase}

;--------------------------------
;Function

; https://nsis.sourceforge.io/RefreshShellIcons
Function RefreshShellIcons
  !define SHCNE_ASSOCCHANGED 0x08000000
  !define SHCNF_IDLIST 0
  System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)'
FunctionEnd

; Start BleachBit as the user who ran setup, not the admin that elevated it
Function RunBleachBit
  HideWindow ; so BleachBit becomes the active window once setup exits
  ${If} ${UAC_IsInnerInstance}
    !insertmacro UAC_AsUser_ExecShell "open" "$INSTDIR\${prodname}.exe" "" "$INSTDIR" ""
  ${Else}
    ; Setup was started elevated, so there is no user instance to ask
    ${StdUtils.ExecShellAsUser} $0 "$INSTDIR\${prodname}.exe" "open" ""
  ${EndIf}
FunctionEnd

; The elevated inner instance starts at the first page again, but the outer
; one already showed these
Function PageWelcomeLicensePre
  ${If} $InstallShowPagesBeforeComponents = 0
    Abort
  ${EndIf}
FunctionEnd

Function .onVerifyInstDir
  ; This callback belongs to MUI_PAGE_DIRECTORY and is called every time the user presses Browse
  ; button and selects install directory. It does not affect typing in the input field.

  ; The purpose is to prevent installation in a shared folder such as %ProgramFiles%
  ; by adding the product name to the end.

  ${GetFileName} $INSTDIR $R0 ; get the last part of the path
  StrCmp $R0 ${prodname} no_append
  StrCpy $INSTDIR "$INSTDIR\${prodname}"
  no_append:
FunctionEnd

;--------------------------------
;Default section
Section "$(SECTION_CORE_NAME)" SectionCore
    SectionIn RO

    !include FilesToInstall.nsh

    # uninstaller
    WriteUninstaller "$INSTDIR\${UNINSTALL_FILENAME}"

    SetOutPath "$INSTDIR\"
    CreateDirectory "$SMPROGRAMS\${prodname}"

    # register uninstaller in Add/Remove Programs
    !insertmacro MULTIUSER_RegistryAddInstallInfo ; add registry keys
    WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" \
        "HelpLink" "https://www.bleachbit.org/help"
    WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" \
        "URLInfoAbout" "https://www.bleachbit.org/"
    WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" \
        "URLUpdateInfo" "https://www.bleachbit.org/download"
    WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" \
                 "DisplayName" "${prodname}"

    # Build cache now while there is a GUI progress bar.
    DetailPrint "$(MULTIPRINT1)"
    DetailPrint "$(MULTIPRINT2)"
    # nsExec runs it without flashing a console window
    nsExec::Exec '"$instdir\fc-cache.exe"'
    Pop $0 ; exit code
SectionEnd


SectionGroup /e "$(SECTION_SHORTCUTS_NAME)" SectionShortCuts
    Section "$(SECTION_START_MENU_NAME)" SectionStart
        SetOutPath "$INSTDIR\" # this affects CreateShortCut's 'Start in' directory
        CreateShortCut "$SMPROGRAMS\${prodname}\${prodname}.lnk" "$INSTDIR\${prodname}.exe" \
            "" "$INSTDIR\${prodname}.exe"
        CreateShortCut "$SMPROGRAMS\${prodname}\$(SHORTCUT_NO_UAC).lnk" \
            "$INSTDIR\${prodname}.exe" \
            "--no-uac --gui" "$INSTDIR\${prodname}.exe"
        CreateShortCut "$SMPROGRAMS\${prodname}\$(SHORTCUT_DEBUGGING_TERMINAL).lnk" \
            "$INSTDIR\${prodname}_console.exe" "" "$INSTDIR\${prodname}.exe"
        Call RefreshShellIcons
    SectionEnd

    Section "$(SECTION_DESKTOP_NAME)" SectionDesktop
        IfSilent 0 addDesktopShortcut
        ${GetParameters} $R0
        ${StrCase} $R0 $R0 "L" # "L" means lowercase
        ${GetOptions} $R0 "/nodesktopshortcut" $R1
        IfErrors addDesktopShortcut doNotAddDesktopShortcut
        addDesktopShortcut:
        SetOutPath "$INSTDIR\" # this affects CreateShortCut's 'Start in' directory
        CreateShortcut "$DESKTOP\BleachBit.lnk" "$INSTDIR\${prodname}.exe"
        Call RefreshShellIcons

        doNotAddDesktopShortcut:

    SectionEnd

    Section /o "$(SECTION_QUICK_LAUNCH_NAME)" SectionQuickLaunch
        SetOutPath "$INSTDIR\" # this affects CreateShortCut's 'Start in' directory
        CreateShortcut "$QUICKLAUNCH\BleachBit.lnk" "$INSTDIR\${prodname}.exe"
        Call RefreshShellIcons
    SectionEnd

SectionGroupEnd


!ifndef NoTranslations
Section "$(SECTION_TRANSLATIONS_NAME)" SectionTranslations
  !include LocaleToInstall.nsh
SectionEnd
!endif

; Section for making Shred Integration optional
!ifndef NoSectionShred
  Section "$(SECTION_INTEGRATE_SHRED_NAME)" SectionShred
    ; Register Windows Explorer Shell Extension (Shredder)
    ; New keys under HKCR go to HKLM, which a per-user install cannot write
    WriteRegStr SHCTX "Software\Classes\${SHRED_REGEX_KEY}" "" '$(SHRED_SHELL_MENU)'
    WriteRegStr SHCTX "Software\Classes\${SHRED_REGEX_KEY}" "Icon" "$INSTDIR\bleachbit.exe,0"
    WriteRegStr SHCTX "Software\Classes\${SHRED_REGEX_KEY}\command" "" '"$INSTDIR\bleachbit.exe" --context-menu "%1"'
  SectionEnd
!endif

; Keep this section last. It must be last because that is when the
; actual size is known.
; This is a hidden section.
Section "-Write Install Size"
    !insertmacro MULTIUSER_RegistryAddInstallSizeInfo
SectionEnd

;--------------------------------
;Installer Functions

!macro SelectSectionIfExists SECTION PATH
  ${If} ${FileExists} "${PATH}"
    !insertmacro SelectSection ${SECTION}
  ${Else}
    !insertmacro UnselectSection ${SECTION}
  ${EndIf}
!macroend

!macro CopySectionFromOuter SECTION
  !insertmacro UAC_AsUser_GetSection Flags ${SECTION} $0
  SectionSetFlags ${SECTION} $0
!macroend

Function .onInit

  ${If} ${AtMostWin8.1}
    MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "$(OLD_WINDOWS_WARNING)" /SD IDOK IDOK open_old_windows_page
    Abort
  ${EndIf}

  !insertmacro MULTIUSER_INIT

  ; Language display dialog
  ; The elevated inner instance already has the language of the outer one
  ${If} $IsInnerInstance = 0
    !insertmacro MUI_LANGDLL_DISPLAY
  ${EndIf}

  ; The outer instance already uninstalled the old version and preselected
  ; its components
  ${If} $IsInnerInstance = 1
    !insertmacro CopySectionFromOuter ${SectionStart}
    !insertmacro CopySectionFromOuter ${SectionDesktop}
    !insertmacro CopySectionFromOuter ${SectionQuickLaunch}
    !ifndef NoTranslations
      !insertmacro CopySectionFromOuter ${SectionTranslations}
    !endif
    !insertmacro CopySectionFromOuter ${SectionShred}
  ${EndIf}

  ; If not already installed, skip uninstallation. The outer instance handles
  ; per-user installations, since HKCU in the elevated one can be the admin's
  ${If} $IsInnerInstance = 0
  ${AndIf} $IsAdmin = 0
    StrCmp "$PerMachineUninstallString$PerUserUninstallString" "" new_install
  ${Else}
    StrCmp $PerMachineUninstallString "" new_install
  ${EndIf}

  MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
    "$(ALREADY_INSTALLED)" \
    /SD IDOK \
    IDOK uninstall_old

  Abort

  uninstall_old:
  ${If} $PerMachineUninstallString != ""
    StrCpy $R0 $PerMachineUninstallString
    StrCpy $R1 $PerMachineInstallationFolder
    ; BleachBit 2.2 and older did not record InstallLocation
    ${IfThen} $R1 == "" ${|} StrCpy $R1 $INSTDIR ${|}
    SetShellVarContext all
    Call UninstallOld
  ${EndIf}
  ; A per-user installation is registered under HKCU instead. Not when
  ; elevated: any process of the user can write that command
  ${If} $PerUserUninstallString != ""
  ${AndIf} $IsInnerInstance = 0
  ${AndIf} $IsAdmin = 0
    StrCpy $R0 $PerUserUninstallString
    StrCpy $R1 $PerUserInstallationFolder
    SetShellVarContext current
    Call UninstallOld
  ${EndIf}
  ${If} $MultiUser.InstallMode == "AllUsers"
    SetShellVarContext all
  ${Else}
    SetShellVarContext current
  ${EndIf}

  new_install:
  Return

  ; On old version of Windows after user agrees to open the link.
  open_old_windows_page:
    ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "CurrentVersion"
    ExecShell "open" "https://www.bleachbit.org/goto/old-windows?ver=${VERSION}&os=$R0&lang=$LANGUAGE"
    Abort

FunctionEnd


; Run the old uninstaller command $R0 on the installation in $R1
Function UninstallOld
  Var /GLOBAL uninstaller_cmd
  Call ReadOldComponents
  StrCpy $uninstaller_cmd $R0
  ; Run a copy so the old uninstaller can delete itself. In place it leaves
  ; uninstall.exe behind and asks for a reboot to remove the folder
  StrCpy $2 '"$R1\${UNINSTALL_FILENAME}"'
  StrLen $3 $2
  StrCpy $4 $R0 $3
  ${If} $4 == $2
    InitPluginsDir
    ClearErrors
    CopyFiles /SILENT "$R1\${UNINSTALL_FILENAME}" "$PLUGINSDIR"
    ${IfNot} ${Errors}
      StrCpy $4 $R0 "" $3
      StrCpy $uninstaller_cmd '"$PLUGINSDIR\${UNINSTALL_FILENAME}"$4'
    ${EndIf}
  ${EndIf}
  ; If installing in silent mode, also uninstall in silent mode
  IfSilent 0 +2
  StrCpy $uninstaller_cmd "$uninstaller_cmd /S"
  ; _?= must come last: NSIS reads the rest of the line as the folder
  StrCpy $uninstaller_cmd "$uninstaller_cmd _?=$R1"
  ; Files in use get deleted at the next reboot, taking the new ones with them
  close_bleachbit:
  Call FindRunningBleachBit
  ${If} $0 != ""
    MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "$(BLEACHBIT_RUNNING)" /SD IDCANCEL IDRETRY close_bleachbit
    Abort
  ${EndIf}
  ClearErrors
  ExecWait $uninstaller_cmd ; Actually run the uninstaller
  ; Catch files still in use, e.g. by another user's BleachBit. Errors mean
  ; the uninstaller failed or was cancelled and queued nothing
  ${IfNot} ${Errors}
    ${If} ${FileExists} "$R1\${prodname}.exe"
    ${OrIf} ${FileExists} "$R1\${prodname}_console.exe"
      MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(MUI_UNTEXT_FINISH_INFO_REBOOT)" /SD IDNO IDNO +2
      Reboot
      Abort
    ${EndIf}
  ${EndIf}
FunctionEnd


; Preselect the optional components the old installation in $R1 has, before
; its uninstaller removes them. Only the first one counts. Clobbers $0.
Function ReadOldComponents
  Var /GLOBAL old_components_read
  ${If} $old_components_read = 1
    Return
  ${EndIf}
  StrCpy $old_components_read 1
  !insertmacro SelectSectionIfExists ${SectionStart} "$SMPROGRAMS\${prodname}\${prodname}.lnk"
  !insertmacro SelectSectionIfExists ${SectionDesktop} "$DESKTOP\BleachBit.lnk"
  !insertmacro SelectSectionIfExists ${SectionQuickLaunch} "$QUICKLAUNCH\BleachBit.lnk"
  !ifndef NoTranslations
    !insertmacro SelectSectionIfExists ${SectionTranslations} "$R1\share\locale\*.*"
  !endif
  ; HKCR covers both the per-machine and the per-user key, but older
  ; per-user installations could not write theirs, so only a per-machine
  ; one shows whether Shred was deselected
  ${If} $R0 == $PerMachineUninstallString
    ReadRegStr $0 HKCR "${SHRED_REGEX_KEY}" ""
    ${If} $0 == ""
      !insertmacro UnselectSection ${SectionShred}
    ${EndIf}
  ${EndIf}
FunctionEnd


; Set $0 to the path of a BleachBit exe running from the folder in $R1, or to
; "" if there is none. Clobbers $1-$7.
Function FindRunningBleachBit
  StrCpy $0 ""
  System::Alloc 16384 ; room for 4096 process IDs
  Pop $1
  System::Call 'kernel32::K32EnumProcesses(p r1, i 16384, *i .r2) i .r3'
  ${If} $3 <> 0
    IntOp $2 $2 - 4
    ${ForEach} $3 0 $2 + 4
      IntPtrOp $4 $1 + $3
      System::Call '*$4(i .r4)'
      ; PROCESS_QUERY_LIMITED_INFORMATION, which also opens elevated processes
      System::Call 'kernel32::OpenProcess(i 0x1000, i 0, i r4) p .r5'
      ${If} $5 <> 0
        System::Call 'kernel32::QueryFullProcessImageName(p r5, i 0, t .r6, *i ${NSIS_MAX_STRLEN}) i .r7'
        System::Call 'kernel32::CloseHandle(p r5)'
        ${If} $7 <> 0
          ${If} $6 == "$R1\${prodname}.exe"
          ${OrIf} $6 == "$R1\${prodname}_console.exe"
            StrCpy $0 $6
            ${ExitFor}
          ${EndIf}
        ${EndIf}
      ${EndIf}
    ${Next}
  ${EndIf}
  System::Free $1
FunctionEnd


;--------------------------------
;Uninstaller Section

UninstallText "$(UNINSTALL_TEXT)"

Section "Uninstall" SectionUninstall
    Delete $INSTDIR\bleachbit.exe.log

    !ifndef NoTranslations
      !include LocaleToUninstall.nsh
    !endif

    !include FilesToUninstall.nsh

    DeleteRegKey HKCU "Software\${prodname}"
    # delete normal shortcuts
    RMDir /r "$SMPROGRAMS\${prodname}"
    # delete any extra shortcuts
    Delete "$DESKTOP\BleachBit.lnk"
    Delete "$QUICKLAUNCH\BleachBit.lnk"
    Delete "$SMSTARTUP\BleachBit.lnk"
    # Remove Windows Explorer Shell Extension (Shredder)
    DeleteRegKey SHCTX "Software\Classes\${SHRED_REGEX_KEY}"

    # The fc-cache run in 6.0.5 wrote its cache here, and the file list above only covers shipped files
    # No RMDir /r, NSIS follows junctions
    Delete "$INSTDIR\var\cache\fontconfig\*.cache-*"
    Delete "$INSTDIR\var\cache\fontconfig\CACHEDIR.TAG"
    RMDir "$INSTDIR\var\cache\fontconfig"
    RMDir "$INSTDIR\var\cache"
    RMDir "$INSTDIR\var"

    # Remove the uninstaller as the very last step.
    # If something goes wrong, let the user run it again.
    Delete "$INSTDIR\${UNINSTALL_FILENAME}"
    # Files the user added, like custom cleaners, are no reason to reboot
    ${If} ${RebootFlag}
        RMDir /REBOOTOK "$INSTDIR\."
    ${Else}
        RMDir "$INSTDIR\."
    ${EndIf}

    # Remove the uninstaller from registry as the very last step.
    # If something goes wrong, let the user run it again.
    !insertmacro MULTIUSER_RegistryRemoveInstallInfo
SectionEnd

;-------------------------------- Set SectionDescription

  ;Assign descriptions to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionCore}         "$(SECTION_CORE_DESCRIPTION)"
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionShortCuts}    "$(SECTION_SHORTCUTS_DESCRIPTION)"
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionStart}        "$(SECTION_START_MENU_DESCRIPTION)"
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionDesktop}      "$(SECTION_DESKTOP_DESCRIPTION)"
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionQuickLaunch}  "$(SECTION_QUICK_LAUNCH_DESCRIPTION)"
    !ifndef NoTranslations
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionTranslations} "$(SECTION_TRANSLATIONS_DESCRIPTION)"
    !endif
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionShred}        "$(SECTION_INTEGRATE_SHRED_DESCRIPTION)"
    !insertmacro MUI_DESCRIPTION_TEXT ${SectionUninstall}    "$(SECTION_UNINSTALL_DESCRIPTION)"
  !insertmacro MUI_FUNCTION_DESCRIPTION_END

;--------------------------------
;Uninstaller Functions

Function un.onInit

  !insertmacro MULTIUSER_UNINIT

  !insertmacro MUI_UNGETLANGUAGE

FunctionEnd