[tbb-commits] [Git][tpo/applications/tor-browser-build][main] 2 commits: Bug 41076: Include the ShellLink plugin in NSIS.

Pier Angelo Vendrame (@pierov) git at gitlab.torproject.org
Tue Feb 13 18:10:17 UTC 2024



Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build


Commits:
a382aeb7 by Pier Angelo Vendrame at 2024-02-13T19:09:27+01:00
Bug 41076: Include the ShellLink plugin in NSIS.

We will need this plugin for the Mullvad Browser uninstaller.

- - - - -
8deb68f2 by Pier Angelo Vendrame at 2024-02-13T19:09:29+01:00
Bug 41077: Draft the new installer for Mullvad Browser.

The installer for Mullvad Browser is going to be different from Tor
Browser's, because it will offer both a traditional installation
(at the moment only for the current user, to avoid enabling privilege
elevation code paths, but still with a control panel entry) and
portable "installations".

The traditional one will support also setting MB as the default
browser and file associations. However, this is quite tricky, and
having a base installer to start implementing the feature is helpful.
Thus this commit, even though the final installer will be likely
changed.

- - - - -


15 changed files:

- projects/browser/build
- projects/browser/config
- − projects/browser/windows-installer.nsi
- + projects/browser/windows-installer/browser-install.nsi
- + projects/browser/windows-installer/browser-portable.nsi
- + projects/browser/windows-installer/common.nsh
- + projects/browser/windows-installer/defines.nsh.in
- + projects/browser/windows-installer/language-map.sh
- + projects/browser/windows-installer/languages.nsh
- + projects/browser/windows-installer/postupdate.nsi
- + projects/browser/windows-installer/registry.nsh
- + projects/nsis/ShellLink.cpp
- projects/nsis/build
- projects/nsis/config
- rbm.conf


Changes:

=====================================
projects/browser/build
=====================================
@@ -303,9 +303,27 @@ done
   export PATH="/var/tmp/dist/nsis/bin:$PATH"
 
   mv $rootdir/windows-installer $distdir/windows-installer
-  cat > $distdir/windows-installer/browser-portable.nsi << 'BROWSER_NSI'
-[% INCLUDE 'windows-installer.nsi' %]
-BROWSER_NSI
+  mv $rootdir/defines.nsh $distdir/windows-installer/
+  [% IF !c('var/testbuild') -%]
+    source $distdir/windows-installer/language-map.sh
+    supported_locales="[% tmpl(c('var/locales').join(' ')) %]"
+    for code in $supported_locales; do
+      if [[ -n ${nsis_languages[$code]} ]]; then
+        echo '!insertmacro MUI_LANGUAGE "'${nsis_languages[$code]}'"' >> $distdir/windows-installer/languages.nsh
+      fi
+    done
+  [% END -%]
+
+  [% IF c('var/mullvad-browser') -%]
+    pushd $distdir/windows-installer
+    # While Firefox re-uses the uninstaller for this, we cannot do it, because
+    # we write the uninstaller from the installer.
+    # Instead, we need to write an updated postupdate.exe also when updating.
+    makensis postupdate.nsi
+    mv postupdate.exe ${TB_STAGE_DIR}/Browser/
+    popd
+  [% END -%]
+
   mv ${TB_STAGE_DIR} $distdir/windows-installer/"[% c('var/Project_Name') %]"
   mv $distdir/windows-installer ${TB_STAGE_DIR}
 [% END %]
@@ -383,8 +401,13 @@ cd $distdir
   pushd "$PKG_DIR"
   makensis browser-portable.nsi
   # Working around NSIS braindamage
-  python3 $rootdir/pe_checksum_fix.py browser-install.exe
-  mv browser-install.exe $OUTDIR/[% c("var/project-name") %]-[% c("var/osname") %]-portable-[% c("var/torbrowser_version") %].exe
+  python3 $rootdir/pe_checksum_fix.py browser-portable.exe
+  mv browser-portable.exe $OUTDIR/[% c("var/project-name") %]-[% c("var/osname") %]-portable-[% c("var/torbrowser_version") %].exe
+  [% IF c('var/mullvad-browser') -%]
+    makensis browser-install.nsi
+    python3 $rootdir/pe_checksum_fix.py browser-install.exe
+    mv browser-install.exe $OUTDIR/[% c("var/project-name") %]-[% c("var/osname") %]-install-[% c("var/torbrowser_version") %].exe
+  [% END -%]
   popd
 [% END %]
 rm -rf $distdir/${PKG_DIR}


=====================================
projects/browser/config
=====================================
@@ -120,6 +120,9 @@ input_files:
     enable: '[% c("var/windows") %]'
   - filename: windows-installer
     enable: '[% c("var/windows") %]'
+  - filename: 'defines.nsh'
+    content: '[% INCLUDE "windows-installer/defines.nsh.in" %]'
+    refresh_input: 1
   - filename: pe_checksum_fix.py
     enable: '[% c("var/windows") %]'
   # To generate a new keystore, see how-to-generate-keystore.txt


=====================================
projects/browser/windows-installer.nsi deleted
=====================================
@@ -1,169 +0,0 @@
-; NSIS Installer for Tor/Base/Mullvad Browser
-; Based on NSIS examples by Joost Verburg.
-; Originally adapted to Tor Browser by Moritz Bartl
-; https://github.com/moba/tbb-windows-installer
-; Released under the zlib/libpng license.
-
-;--------------------------------
-  !include "FileFunc.nsh"
-  !include "LogicLib.nsh"
-  !include "MUI2.nsh"
-  !include "WinVer.nsh"
-
-;--------------------------------
-; General
-  ; Location of Tor/Base/Mullvad Browser to put into installer
-  !define PROGRAM_SOURCE ".\[% c('var/Project_Name') %]\"
-
-[% IF c("var/channel") == "release";
-      SET display_name = c('var/Project_Name');
-   ELSIF c("var/testbuild");
-      SET display_name = c('var/Project_Name') _ " Testbuild";
-   ELSE;
-      SET display_name = c('var/Project_Name_Channel');
-   END
--%]
-  Name "[% display_name %]"
-  OutFile "browser-install.exe"
-
-  ; Default installation folder
-  InstallDir "$DESKTOP\[% display_name %]"
-
-  ; Best (but slowest) compression
-  SetCompressor /SOLID lzma
-  SetCompressorDictSize 32
-
-  ; Do not require elevated privileges
-  RequestExecutionLevel user
-
-  ; Support HiDPI displays
-  ManifestDPIAware true
-
-;--------------------------------
-; Metadata
-  VIProductVersion "[% pc('firefox', 'var/browser_series') %].0.0"
-  VIAddVersionKey "ProductName" "[% display_name %]"
-  VIAddVersionKey "ProductVersion" "[% c('var/torbrowser_version') %]"
-  VIAddVersionKey "FileDescription" "[% display_name %] Portable Installer"
-  VIAddVersionKey "LegalCopyright" "© [% pc('firefox', 'var/copyright_year') %] [% IF c('var/mullvad-browser') %]Mullvad, Tor Browser and Mozilla Developers[% ELSE %]The Tor Project[% END %]"
-
-;--------------------------------
-; Interface Configuration
-  !define MUI_ICON "[% c('var/projectname') %][% IF !c('var/base-browser') %]-[% c('var/channel') %][% END %].ico"
-  !define MUI_ABORTWARNING
-
-;--------------------------------
-; Modern UI settings
-  !define MUI_FINISHPAGE_NOREBOOTSUPPORT ; Reboot not required
-  !define MUI_FINISHPAGE_RUN
-  !define MUI_FINISHPAGE_RUN_FUNCTION "StartBrowser"
-
-  ; Misuse the option to show the readme to create the shortcuts.
-  ; Less ugly than MUI_PAGE_COMPONENTS.
-  !define MUI_FINISHPAGE_SHOWREADME
-  !define MUI_FINISHPAGE_SHOWREADME_TEXT "&Add Start Menu && Desktop shortcuts"
-  !define MUI_FINISHPAGE_SHOWREADME_FUNCTION "CreateShortCuts"
-
-;--------------------------------
-; Pages
-  !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckIfTargetDirectoryExists
-  !insertmacro MUI_PAGE_DIRECTORY
-  !insertmacro MUI_PAGE_INSTFILES
-  !insertmacro MUI_PAGE_FINISH
-
-;--------------------------------
-; Languages
-  !insertmacro MUI_LANGUAGE "English" ; First language is the default language
-  !insertmacro MUI_LANGUAGE "Arabic" ; ar
-  !insertmacro MUI_LANGUAGE "Catalan" ; ca
-  !insertmacro MUI_LANGUAGE "Czech" ; cs
-  !insertmacro MUI_LANGUAGE "Danish" ; da
-  !insertmacro MUI_LANGUAGE "German" ; de
-  !insertmacro MUI_LANGUAGE "Greek" ; el
-  !insertmacro MUI_LANGUAGE "Spanish" ; es-ES
-  !insertmacro MUI_LANGUAGE "Farsi" ; fa
-  !insertmacro MUI_LANGUAGE "Finnish" ; fi
-  !insertmacro MUI_LANGUAGE "French" ; fr
-  !insertmacro MUI_LANGUAGE "ScotsGaelic" ; ga-IE
-  !insertmacro MUI_LANGUAGE "Hebrew" ; he
-  !insertmacro MUI_LANGUAGE "Hungarian" ; hu
-  !insertmacro MUI_LANGUAGE "Indonesian"; id
-  !insertmacro MUI_LANGUAGE "Icelandic" ; is
-  !insertmacro MUI_LANGUAGE "Italian" ; it
-  !insertmacro MUI_LANGUAGE "Japanese" ; ja
-  !insertmacro MUI_LANGUAGE "Georgian" ; ka
-  !insertmacro MUI_LANGUAGE "Korean" ; ko
-  !insertmacro MUI_LANGUAGE "Lithuanian" ; lt
-  !insertmacro MUI_LANGUAGE "Macedonian" ; mk
-  !insertmacro MUI_LANGUAGE "Malay" ; ms
-  ; Burmese - my: not available on NSIS
-  !insertmacro MUI_LANGUAGE "Norwegian" ; nb-NO
-  !insertmacro MUI_LANGUAGE "Dutch" ; nl
-  !insertmacro MUI_LANGUAGE "Polish" ; pl
-  !insertmacro MUI_LANGUAGE "PortugueseBR" ; pt-BR
-  !insertmacro MUI_LANGUAGE "Romanian" ; ro
-  !insertmacro MUI_LANGUAGE "Russian" ; ru
-  !insertmacro MUI_LANGUAGE "Albanian" ; sq
-  !insertmacro MUI_LANGUAGE "Swedish" ; sv-SE
-  !insertmacro MUI_LANGUAGE "Thai" ; th
-  !insertmacro MUI_LANGUAGE "Turkish" ; tr
-  !insertmacro MUI_LANGUAGE "Ukrainian" ; uk
-  !insertmacro MUI_LANGUAGE "Vietnamese" ; vi
-  !insertmacro MUI_LANGUAGE "SimpChinese" ; zh-hans, zh-cn
-  !insertmacro MUI_LANGUAGE "TradChinese" ; zh-hant, zh-tw
-
-;--------------------------------
-; Reserve Files
-
-  ; If you are using solid compression, files that are required before
-  ; the actual installation should be stored first in the data block,
-  ; because this will make your installer start faster.
-
-  !insertmacro MUI_RESERVEFILE_LANGDLL
-
-;--------------------------------
-; Installer Sections
-
-Section "Browser" SecBrowser
-  SetOutPath "$INSTDIR"
-  File /r "${PROGRAM_SOURCE}\*.*"
-  CreateShortCut "$INSTDIR\[% display_name %].lnk" "$INSTDIR\Browser\[% c('var/exe_name') %].exe"
-SectionEnd
-
-;--------------------------------
-; Installer Functions
-
-Function .onInit
-  ${IfNot} ${AtLeastWin7}
-    MessageBox MB_USERICON|MB_OK "[% c('var/Project_Name') %] requires at least Windows 7"
-    SetErrorLevel 1
-    Quit
-  ${EndIf}
-
-  ; Don't install on systems that don't support SSE2. The parameter value of
-  ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the
-  ; SSE2 instruction set is available.
-  System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R7"
-  ${If} "$R7" == "0"
-    MessageBox MB_OK|MB_ICONSTOP "Sorry, [% c('var/Project_Name') %] can't be installed. This version of [% c('var/Project_Name') %] requires a processor with SSE2 support."
-    Abort
-  ${EndIf}
-
-  !insertmacro MUI_LANGDLL_DISPLAY
-FunctionEnd
-
-Function CheckIfTargetDirectoryExists
-  ${If} ${FileExists} "$INSTDIR\*.*"
-    MessageBox MB_YESNO "The destination directory already exists. Do you want to continue anyway?" IDYES +2
-    Abort
-  ${EndIf}
-FunctionEnd
-
-Function CreateShortcuts
-  CreateShortCut "$SMPROGRAMS\[% display_name %].lnk" "$INSTDIR\[% IF !system_install_mode -%]Browser\[% END -%][% c('var/exe_name') %].exe"
-  CreateShortCut "$DESKTOP\[% display_name %].lnk" "$INSTDIR\[% IF !system_install_mode -%]Browser\[% END -%][% c('var/exe_name') %].exe"
-FunctionEnd
-
-Function StartBrowser
-  ExecShell "open" "$INSTDIR/[% display_name %].lnk"
-FunctionEnd


=====================================
projects/browser/windows-installer/browser-install.nsi
=====================================
@@ -0,0 +1,263 @@
+  !include "common.nsh"
+  !include "registry.nsh"
+
+;--------------------------------
+  OutFile "browser-install.exe"
+  VIAddVersionKey "FileDescription" "${DISPLAY_NAME} Installer"
+
+  !define DEFAULT_INSTALL_DIR "$LocalAppdata\${APP_DIR}\${NAME_NO_SPACES}\${UPDATE_CHANNEL}"
+  InstallDir "${DEFAULT_INSTALL_DIR}"
+
+;--------------------------------
+; Pages
+  Page custom SetupType SetupTypeLeave
+  Page custom CustomSetup CustomSetupLeave
+  ; Disable the directory selection when updating
+  !define MUI_PAGE_CUSTOMFUNCTION_PRE CustomPageDirectory
+  !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckIfTargetDirectoryExists
+  !insertmacro MUI_PAGE_DIRECTORY
+  !insertmacro MUI_PAGE_INSTFILES
+  !insertmacro MUI_PAGE_FINISH
+
+  !insertmacro MUI_UNPAGE_CONFIRM
+  !insertmacro MUI_UNPAGE_INSTFILES
+  !insertmacro MUI_UNPAGE_FINISH
+
+  ; Languages must be defined after pages
+  !include "languages.nsh"
+
+;--------------------------------
+; Installer
+
+; Path to an existing install. If not empty we are in update mode.
+var existingInstall
+
+; Installation settings
+var isCustomMode
+var isPortableMode
+var createDesktopShortcut
+
+; Variable used by the setup type page
+var typeRadioStandard
+var typeRadioCustom
+var typeRadioClicked
+var typeNextButton
+
+; Variables used in the custom setup page
+var customCheckboxPortable
+var customCheckboxDesktop
+
+Function .onInit
+  Call CheckRequirements
+
+  !insertmacro MUI_LANGDLL_DISPLAY
+
+  ReadRegStr $existingInstall HKCU "${UNINST_KEY}" "InstallLocation"
+  StrCpy $createDesktopShortcut "true"
+FunctionEnd
+
+Function SetupType
+  !insertmacro MUI_HEADER_TEXT "Setup Type" "Choose setup options"
+  nsDialogs::Create 1018
+  Pop $0
+  ${If} $0 == error
+    Abort
+  ${EndIf}
+
+  ${NSD_CreateLabel} 0 0 100% 18% "Choose the type of setup you prefer."
+  ${If} $existingInstall == ""
+    ${NSD_CreateRadioButton} 0 18% 100% 6% "Standard"
+    Pop $typeRadioStandard
+    ${NSD_CreateRadioButton} 0 30% 100% 6% "Custom"
+    Pop $typeRadioCustom
+  ${Else}
+    ${NSD_CreateRadioButton} 0 18% 100% 6% "Update your existing installation"
+    Pop $typeRadioStandard
+    ${NSD_CreateRadioButton} 0 30% 100% 6% "Portable installation"
+    Pop $typeRadioCustom
+  ${EndIf}
+  ${NSD_OnClick} $typeRadioStandard SetupTypeRadioClick
+  ${NSD_OnClick} $typeRadioCustom SetupTypeRadioClick
+
+  GetDlgItem $typeNextButton $HWNDPARENT 1
+
+  ; Re-check radios if the user presses back
+  ${If} $isCustomMode == "true"
+    StrCpy $typeRadioClicked $typeRadioCustom
+  ${Else}
+    StrCpy $typeRadioClicked $typeRadioStandard
+  ${EndIf}
+  ${NSD_Check} $typeRadioClicked
+  Call SetupTypeUpdate
+
+  nsDialogs::Show
+FunctionEnd
+
+Function SetupTypeRadioClick
+  Pop $typeRadioClicked
+  Call SetupTypeUpdate
+FunctionEnd
+
+Function SetupTypeUpdate
+  ${If} $typeRadioClicked == $typeRadioCustom
+    StrCpy $isCustomMode "true"
+    SendMessage $typeNextButton ${WM_SETTEXT} 0 "STR:$(^NextBtn)"
+  ${ElseIf} $typeRadioClicked == $typeRadioStandard
+    StrCpy $isCustomMode "false"
+    StrCpy $isPortableMode "false"
+    ${If} $existingInstall == ""
+      SendMessage $typeNextButton ${WM_SETTEXT} 0 "STR:$(^InstallBtn)"
+    ${Else}
+      SendMessage $typeNextButton ${WM_SETTEXT} 0 "STR:&Update"
+    ${EndIf}
+  ${EndIf}
+FunctionEnd
+
+Function SetupTypeLeave
+  ${If} $typeRadioClicked == $typeRadioCustom
+    StrCpy $isCustomMode "true"
+  ${ElseIf} $typeRadioClicked == $typeRadioStandard
+    StrCpy $isCustomMode "false"
+    StrCpy $isPortableMode "false"
+  ${Else}
+    Abort
+  ${EndIf}
+FunctionEnd
+
+Function CustomSetup
+  ${If} $isCustomMode != "true"
+    Return
+  ${EndIf}
+
+  !insertmacro MUI_HEADER_TEXT "Custom Setup" "Customize your setup options"
+  nsDialogs::Create 1018
+  Pop $0
+  ${If} $0 == error
+    Abort
+  ${EndIf}
+
+  ${NSD_CreateCheckbox} 0 18% 100% 6% "Portable installation"
+  Pop $customCheckboxPortable
+  ${NSD_CreateCheckbox} 0 30% 100% 6% "Create a desktop shortcut"
+  Pop $customCheckboxDesktop
+  ${NSD_OnClick} $customCheckboxPortable CustomSetupCheckboxClick
+  ${NSD_OnClick} $customCheckboxDesktop CustomSetupCheckboxClick
+
+  ${If} $existingInstall != ""
+    ; If we already have an installation, this is already portable mode.
+    StrCpy $isPortableMode "true"
+    ${NSD_Check} $customCheckboxPortable
+    EnableWindow $customCheckboxPortable 0
+  ${ElseIf} $isPortableMode == "true"
+    ${NSD_Check} $customCheckboxPortable
+  ${EndIf}
+  ${If} $createDesktopShortcut == "true"
+    ${NSD_Check} $customCheckboxDesktop
+  ${EndIf}
+
+  nsDialogs::Show
+FunctionEnd
+
+Function CustomSetupUpdate
+  ${NSD_GetState} $customCheckboxPortable $0
+  ${If} $0 == "${BST_CHECKED}"
+    StrCpy $isPortableMode "true"
+  ${Else}
+    StrCpy $isPortableMode "false"
+  ${EndIf}
+
+  ${NSD_GetState} $customCheckboxDesktop $0
+  ${If} $0 == "${BST_CHECKED}"
+    StrCpy $createDesktopShortcut "true"
+  ${Else}
+    StrCpy $createDesktopShortcut "false"
+  ${EndIf}
+FunctionEnd
+
+Function CustomSetupCheckboxClick
+  Pop $0
+  Call CustomSetupUpdate
+FunctionEnd
+
+Function CustomSetupLeave
+  Call CustomSetupUpdate
+FunctionEnd
+
+Function CustomPageDirectory
+  ${If} $isPortableMode == "true"
+    StrCpy $INSTDIR "${DEFAULT_PORTABLE_DIR}"
+    ; Always go through this page in portable mode.
+    Return
+  ${ElseIf} $existingInstall != ""
+    ; When updating, force the old directory and skip the page.
+    StrCpy $INSTDIR $existingInstall
+    Abort
+  ${Else}
+    StrCpy $INSTDIR "${DEFAULT_INSTALL_DIR}"
+  ${EndIf}
+
+  ${If} $isCustomMode != "true"
+    ; Standard install, use the default directory and skip the page.
+    Abort
+  ${EndIf}
+FunctionEnd
+
+Section "Browser" SecBrowser
+  SetOutPath "$INSTDIR"
+
+  ${If} $isPortableMode == "true"
+    File /r "${PROGRAM_SOURCE}\*.*"
+    CreateShortCut "$INSTDIR\${DISPLAY_NAME}.lnk" "$INSTDIR\Browser\${EXE_NAME}"
+  ${Else}
+    ; Do not use a Browser directory for installs.
+    File /r "${PROGRAM_SOURCE}\Browser\*.*"
+
+    ; Tell the browser we are not in portable mode anymore.
+    FileOpen $0 "$INSTDIR\system-install" w
+    FileClose $0
+
+    ; Write the uninstaller
+    WriteUninstaller $INSTDIR\uninstall.exe
+
+    !insertmacro UPDATE_REGISTRY
+
+    CreateShortCut "$SMPROGRAMS\${DISPLAY_NAME}.lnk" "$INSTDIR\${EXE_NAME}"
+    ${If} $createDesktopShortcut == "true"
+      CreateShortCut "$DESKTOP\${DISPLAY_NAME}.lnk" "$INSTDIR\${EXE_NAME}"
+    ${EndIf}
+  ${EndIf}
+SectionEnd
+
+Function StartBrowser
+  ${If} $isPortableMode == "true"
+    ExecShell "open" "$INSTDIR\${DISPLAY_NAME}.lnk"
+  ${Else}
+    ExecShell "open" "$INSTDIR\${EXE_NAME}"
+  ${EndIf}
+FunctionEnd
+
+;--------------------------------
+; Uninstaller
+Section "Uninstall"
+  RMDir /r "$INSTDIR"
+  DeleteRegKey HKCU "${UNINST_KEY}"
+
+  StrCpy $0 ""
+  ShellLink::GetShortCutTarget "$SMPROGRAMS\${DISPLAY_NAME}.lnk"
+  Pop $0
+  ${If} $0 == "$INSTDIR\${EXE_NAME}"
+    Delete "$SMPROGRAMS\${DISPLAY_NAME}.lnk"
+  ${EndIf}
+
+  StrCpy $0 ""
+  ShellLink::GetShortCutTarget "$DESKTOP\${DISPLAY_NAME}.lnk"
+  Pop $0
+  ${If} $0 == "$INSTDIR\${EXE_NAME}"
+    Delete "$DESKTOP\${DISPLAY_NAME}.lnk"
+  ${EndIf}
+
+  ; TODO: Optionally remove profiles.
+  ; This operation is not trivial, because it involes finding our installation
+  ; hash, its associated default profile and making sure it is not shared with
+  ; another channel/installation.
+SectionEnd


=====================================
projects/browser/windows-installer/browser-portable.nsi
=====================================
@@ -0,0 +1,45 @@
+  !include "common.nsh"
+
+;--------------------------------
+  OutFile "browser-portable.exe"
+  VIAddVersionKey "FileDescription" "${DISPLAY_NAME} Portable Installer"
+  InstallDir "$DESKTOP\${DISPLAY_NAME}"
+
+;--------------------------------
+; Pages
+  ; Misuse the option to show the readme to create the shortcuts.
+  ; Less ugly than MUI_PAGE_COMPONENTS.
+  !define MUI_FINISHPAGE_SHOWREADME
+  !define MUI_FINISHPAGE_SHOWREADME_TEXT "&Add Start Menu && Desktop shortcuts"
+  !define MUI_FINISHPAGE_SHOWREADME_FUNCTION "CreateShortcuts"
+
+  !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckIfTargetDirectoryExists
+  !insertmacro MUI_PAGE_DIRECTORY
+  !insertmacro MUI_PAGE_INSTFILES
+  !insertmacro MUI_PAGE_FINISH
+
+  ; Languages must be defined after pages
+  !include "languages.nsh"
+
+;--------------------------------
+; Installer
+Function .onInit
+  Call CheckRequirements
+
+  !insertmacro MUI_LANGDLL_DISPLAY
+FunctionEnd
+
+Section "Browser" SecBrowser
+  SetOutPath "$INSTDIR"
+  File /r "${PROGRAM_SOURCE}\*.*"
+  CreateShortCut "$INSTDIR\${DISPLAY_NAME}.lnk" "$INSTDIR\Browser\${EXE_NAME}"
+SectionEnd
+
+Function CreateShortcuts
+  CreateShortCut "$SMPROGRAMS\${DISPLAY_NAME}.lnk" "$INSTDIR\Browser\${EXE_NAME}"
+  CreateShortCut "$DESKTOP\${DISPLAY_NAME}.lnk" "$INSTDIR\Browser\${EXE_NAME}"
+FunctionEnd
+
+Function StartBrowser
+  ExecShell "open" "$INSTDIR/${DISPLAY_NAME}.lnk"
+FunctionEnd


=====================================
projects/browser/windows-installer/common.nsh
=====================================
@@ -0,0 +1,82 @@
+; Common code for the NSIS Installers for Tor/Base/Mullvad Browser.
+; Based on NSIS examples by Joost Verburg.
+; Originally adapted to Tor Browser by Moritz Bartl
+; https://github.com/moba/tbb-windows-installer
+; Released under the zlib/libpng license.
+
+;--------------------------------
+  !include "FileFunc.nsh"
+  !include "LogicLib.nsh"
+  !include "MUI2.nsh"
+  !include "WinVer.nsh"
+
+  !include "defines.nsh"
+
+;--------------------------------
+; General settings
+  Name "${DISPLAY_NAME}"
+
+  ; Best (but slowest) compression
+  SetCompressor /SOLID lzma
+  SetCompressorDictSize 32
+
+  ; Do not require elevated privileges.
+  ; Even for the installer, we install only for the current user, so we do not
+  ; need high privileges.
+  RequestExecutionLevel user
+
+  ; Support HiDPI displays
+  ManifestDPIAware true
+
+;--------------------------------
+; Version information
+  VIProductVersion "${VERSION_WINDOWS}"
+  VIAddVersionKey "ProductName" "${DISPLAY_NAME}"
+  VIAddVersionKey "ProductVersion" "${VERSION}"
+  VIAddVersionKey "FileVersion" "${VERSION}"
+  VIAddVersionKey "LegalCopyright" "${COPYRIGHT_STRING}"
+
+;--------------------------------
+; Interface Configuration
+  ; Installer icon
+  !define MUI_ICON "${ICON_NAME}"
+  !define MUI_ABORTWARNING
+
+;--------------------------------
+; Modern UI settings
+  !define MUI_FINISHPAGE_NOREBOOTSUPPORT ; Reboot not required
+  !define MUI_FINISHPAGE_RUN
+  !define MUI_FINISHPAGE_RUN_FUNCTION "StartBrowser"
+
+;--------------------------------
+; Reserve Files
+  ; If you are using solid compression, files that are required before
+  ; the actual installation should be stored first in the data block,
+  ; because this will make your installer start faster.
+  !insertmacro MUI_RESERVEFILE_LANGDLL
+
+;--------------------------------
+; Helper functions
+Function CheckRequirements
+  ${IfNot} ${AtLeastWin7}
+    MessageBox MB_USERICON|MB_OK "${PROJECT_NAME} requires at least Windows 7"
+    SetErrorLevel 1
+    Quit
+  ${EndIf}
+
+  ; Don't install on systems that don't support SSE2. The parameter value of
+  ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the
+  ; SSE2 instruction set is available.
+  System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R7"
+  ${If} "$R7" == "0"
+    MessageBox MB_OK|MB_ICONSTOP "${PROJECT_NAME} requires a processor with SSE2 support."
+    Quit
+  ${EndIf}
+FunctionEnd
+
+Function CheckIfTargetDirectoryExists
+  ${If} ${FileExists} "$INSTDIR\*.*"
+    MessageBox MB_YESNO "The destination directory already exists. Do you want to continue anyway?" IDYES +2
+    Abort
+  ${EndIf}
+FunctionEnd


=====================================
projects/browser/windows-installer/defines.nsh.in
=====================================
@@ -0,0 +1,52 @@
+;--------------------------------
+; Defines
+  ; Location of Tor/Base/Mullvad Browser to put into installer
+  !define PROGRAM_SOURCE ".\[% c('var/Project_Name') %]\"
+
+  ; Project and display name
+  !define PROJECT_NAME "[% c('var/Project_Name') %]"
+[% IF c("var/channel") == "release" -%]
+  !define DISPLAY_NAME "[% c('var/Project_Name') %]"
+[% ELSIF c("var/testbuild") -%]
+  !define DISPLAY_NAME "[% c('var/Project_Name') %] Testbuild"
+[% ELSE -%]
+  !define DISPLAY_NAME "[% c('var/Project_Name_Channel') %]"
+[% END -%]
+  !define NAME_NO_SPACES "[% c('var/ProjectName') %]"
+  !define UPDATE_CHANNEL "[% c('var/channel') FILTER ucfirst %]"
+
+  ; Version
+  !define VERSION "[% c('var/torbrowser_version') %]"
+  ; String for use with Windows's Product Version.
+  ; It must be 4 integers separated by a dot.
+  !define VERSION_WINDOWS "[% pc('firefox', 'var/browser_series') %].0.0"
+
+  !define DEFAULT_PORTABLE_DIR "$DESKTOP\${DISPLAY_NAME}"
+  !define EXE_NAME "[% c('var/exe_name') %].exe"
+[% IF !c("var/base-browser") -%]
+  !define ICON_NAME "[% c('var/projectname') %]-[% c('var/channel') %].ico"
+[% ELSE -%]
+  !define ICON_NAME "[% c('var/projectname') %].ico"
+[% END -%]
+
+[% IF c('var/mullvad-browser') -%]
+  ; Firefox's --with-user-appdir
+  !define APP_DIR "Mullvad"
+
+  !define PUBLISHER "Mullvad VPN"
+  !define COPYRIGHT_STRING "© [% pc('firefox', 'var/copyright_year') %] Mullvad, Tor Browser and Mozilla Developers"
+
+  !define URL_ABOUT "https://mullvad.net/en/browser"
+  !define URL_UPDATE "https://github.com/mullvad/mullvad-browser/releases/[% c('var/torbrowser_version') %]"
+  !define URL_HELP "https://mullvad.net/help/tag/browser/"
+[% ELSE -%]
+  ; Not defined for Tor Browser
+  !define APP_DIR "TorProject"
+
+  !define PUBLISHER "The Tor Project"
+  !define COPYRIGHT_STRING "© [% pc('firefox', 'var/copyright_year') %] The Tor Project"
+
+  !define URL_ABOUT "https://www.torproject.org/"
+  !define URL_UPDATE "https://blog.torproject.org/new[% IF c('var/alpha') %]-alpha[% END %]-release-tor-browser-[% c('var/torbrowser_version') FILTER remove('\.') %]"
+  !define URL_HELP "https://tb-manual.torproject.org/"
+[% END -%]


=====================================
projects/browser/windows-installer/language-map.sh
=====================================
@@ -0,0 +1,39 @@
+#!/bin/bash
+declare -A nsis_languages
+nsis_languages[ar]="Arabic"
+nsis_languages[ca]="Catalan"
+nsis_languages[cs]="Czech"
+nsis_languages[da]="Danish"
+nsis_languages[de]="German"
+nsis_languages[el]="Greek"
+nsis_languages[es-ES]="Spanish"
+nsis_languages[fa]="Farsi"
+nsis_languages[fi]="Finnish"
+nsis_languages[fr]="French"
+nsis_languages[ga-IE]="ScotsGaelic"
+nsis_languages[he]="Hebrew"
+nsis_languages[hu]="Hungarian"
+nsis_languages[d]="Indonesian"
+nsis_languages[is]="Icelandic"
+nsis_languages[it]="Italian"
+nsis_languages[ja]="Japanese"
+nsis_languages[ka]="Georgian"
+nsis_languages[ko]="Korean"
+nsis_languages[lt]="Lithuanian"
+nsis_languages[mk]="Macedonian"
+nsis_languages[ms]="Malay"
+# nsis_languages[my]="Burmese" # Not available on NSIS
+nsis_languages[nb-NO]="Norwegian"
+nsis_languages[nl]="Dutch"
+nsis_languages[pl]="Polish"
+nsis_languages[pt-BR]="PortugueseBR"
+nsis_languages[ro]="Romanian"
+nsis_languages[ru]="Russian"
+nsis_languages[sq]="Albanian"
+nsis_languages[sv-SE]="Swedish"
+nsis_languages[th]="Thai"
+nsis_languages[tr]="Turkish"
+nsis_languages[uk]="Ukrainian"
+nsis_languages[vi]="Vietnamese"
+nsis_languages[zh-CN]="SimpChinese"
+nsis_languages[zh-TW]="TradChinese"


=====================================
projects/browser/windows-installer/languages.nsh
=====================================
@@ -0,0 +1,4 @@
+;--------------------------------
+; Additional languages
+  !insertmacro MUI_LANGUAGE "English" ; Always available
+  ; The rest of the languages will be added here during the build.


=====================================
projects/browser/windows-installer/postupdate.nsi
=====================================
@@ -0,0 +1,28 @@
+!include "FileFunc.nsh"
+!include "LogicLib.nsh"
+
+!include "defines.nsh"
+!include "registry.nsh"
+
+OutFile "postupdate.exe"
+Icon "${ICON_NAME}"
+RequestExecutionLevel user
+
+Function .onInit
+  ${GetOptions} $CMDLINE "/Visible" $0
+  IfErrors 0 +2
+  SetSilent silent
+FunctionEnd
+
+Section PostUpdate "PostUpdate"
+  StrCpy $0 "false"
+  IfFileExists $EXEDIR\system-install 0 +2
+  StrCpy $0 "true"
+  ${If} $0 == "true"
+    StrCpy $INSTDIR $EXEDIR
+    !insertmacro UPDATE_REGISTRY
+    RMDir /r /REBOOTOK $EXEDIR\tobedeleted
+  ${Else}
+    RMDir /r $EXEDIR\tobedeleted
+  ${EndIf}
+SectionEnd


=====================================
projects/browser/windows-installer/registry.nsh
=====================================
@@ -0,0 +1,19 @@
+!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME_NO_SPACES}${UPDATE_CHANNEL}"
+
+!macro UPDATE_REGISTRY
+  WriteRegStr HKCU "${UNINST_KEY}" "DisplayName" "${DISPLAY_NAME}"
+  WriteRegStr HKCU "${UNINST_KEY}" "DisplayIcon" "$\"$INSTDIR\${EXE_NAME}$\""
+  WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "${VERSION}"
+  WriteRegStr HKCU "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
+  WriteRegStr HKCU "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
+  WriteRegDWORD HKCU "${UNINST_KEY}" "NoModify" "1"
+  WriteRegDWORD HKCU "${UNINST_KEY}" "NoRepair" "1"
+  ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
+  IntFmt $0 "0x%08X" $0
+  WriteRegDWORD HKCU "${UNINST_KEY}" "EstimatedSize" "$0"
+  WriteRegStr HKCU "${UNINST_KEY}" "InstallLocation" "$INSTDIR"
+    WriteRegStr HKCU "${UNINST_KEY}" "Publisher" "${PUBLISHER}"
+  WriteRegStr HKCU "${UNINST_KEY}" "URLInfoAbout" "${URL_ABOUT}"
+  WriteRegStr HKCU "${UNINST_KEY}" "URLUpdateInfo" "${URL_UPDATE}"
+  WriteRegStr HKCU "${UNINST_KEY}" "HelpLink" "${URL_HELP}"
+!macroend


=====================================
projects/nsis/ShellLink.cpp
=====================================
@@ -0,0 +1,358 @@
+/*
+Module : ShellLink.cpp
+Purpose: NSIS Plug-in for retriving shell link information
+Created: 12/16/2003
+Last Update: 01/14/2004
+                          
+Copyright (c) 2004 Angelo Mandato.  
+See ShellLink.html for more information
+
+
+Modified: 21/09/2005
+Author:   Shengalts Aleksander aka Instructor (Shengalts at mail.ru)
+Changes:  -code has been rewritten
+          -added functions to change shell link information
+          -reduced dll size 44Kb -> 4Kb
+
+Modified by The Tor Project to remove the unneeded ConvFunc.h and updated the
+include for pluginapi.h.
+The original plugin is available at https://nsis.sourceforge.io/ShellLink_plug-in.
+
+© 2004 Angelo Mandato
+
+This software is provided 'as-is', without any express or implied warranty. In
+no event will the authors be held liable for any damages arising from the use of
+this software.
+
+Permission is granted to anyone to use this software for any purpose, including
+commercial applications, and to alter it and redistribute it freely, subject to
+the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim
+   that you wrote the original software. If you use this software in a product,
+   an acknowledgment in the product documentation would be appreciated but is
+   not required.
+2. Altered versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+3. This notice may not be removed or altered from any distribution.
+
+*/
+
+//  Uncomment for debugging message boxes
+//#define SHELLLINK_DEBUG
+
+#include <windows.h>
+#include <shlobj.h>
+
+#define xatoi
+#include "nsis/pluginapi.h"
+
+#define NSISFUNC(name) extern "C" void __declspec(dllexport) name(HWND hWndParent, int string_size, TCHAR* variables, stack_t** stacktop, extra_parameters* extra)
+
+#define SHELLLINKTYPE_GETARGS 1
+#define SHELLLINKTYPE_GETDESC 2
+#define SHELLLINKTYPE_GETHOTKEY 3
+#define SHELLLINKTYPE_GETICONLOC 4
+#define SHELLLINKTYPE_GETICONINDEX 5
+#define SHELLLINKTYPE_GETPATH 6
+#define SHELLLINKTYPE_GETSHOWMODE 7
+#define SHELLLINKTYPE_GETWORKINGDIR 8
+#define SHELLLINKTYPE_SETARGS 9
+#define SHELLLINKTYPE_SETDESC 10
+#define SHELLLINKTYPE_SETHOTKEY 11
+#define SHELLLINKTYPE_SETICONLOC 12
+#define SHELLLINKTYPE_SETICONINDEX 13
+#define SHELLLINKTYPE_SETPATH 14
+#define SHELLLINKTYPE_SETSHOWMODE 15
+#define SHELLLINKTYPE_SETWORKINGDIR 16
+#define SHELLLINKTYPE_SETRUNASADMIN 17
+
+void ShortCutData(int nType);
+
+//Get
+NSISFUNC(GetShortCutArgs)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETARGS);
+}
+
+NSISFUNC(GetShortCutDescription)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETDESC);
+}
+
+NSISFUNC(GetShortCutHotkey)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETHOTKEY);
+}
+
+NSISFUNC(GetShortCutIconLocation)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETICONLOC);
+}
+
+NSISFUNC(GetShortCutIconIndex)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETICONINDEX);
+}
+
+NSISFUNC(GetShortCutTarget)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETPATH);
+}
+
+NSISFUNC(GetShortCutShowMode)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETSHOWMODE);
+}
+
+NSISFUNC(GetShortCutWorkingDirectory)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_GETWORKINGDIR);
+}
+
+//Set
+NSISFUNC(SetShortCutArgs)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETARGS);
+}
+
+NSISFUNC(SetShortCutDescription)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETDESC);
+}
+
+NSISFUNC(SetShortCutHotkey)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETHOTKEY);
+}
+
+NSISFUNC(SetShortCutIconLocation)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETICONLOC);
+}
+
+NSISFUNC(SetShortCutIconIndex)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETICONINDEX);
+}
+
+NSISFUNC(SetShortCutTarget)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETPATH);
+}
+
+NSISFUNC(SetShortCutShowMode)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETSHOWMODE);
+}
+
+NSISFUNC(SetShortCutWorkingDirectory)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETWORKINGDIR);
+}
+
+NSISFUNC(SetRunAsAdministrator)
+{
+  EXDLL_INIT();
+	ShortCutData(SHELLLINKTYPE_SETRUNASADMIN);
+}
+
+void ShortCutData(int nType)
+{
+	HRESULT hRes;
+	IShellLink* psl;
+	IPersistFile* ppf;
+
+  int nBuf;
+  WORD wHotkey;
+  TCHAR* szBuf = (TCHAR*)LocalAlloc(LPTR, sizeof(TCHAR)*MAX_PATH);
+  TCHAR* szBuf2 = (TCHAR*)LocalAlloc(LPTR, sizeof(TCHAR)*MAX_PATH);
+
+	popstring(szBuf);
+	if (nType > SHELLLINKTYPE_GETWORKINGDIR) popstring(szBuf2);
+
+	hRes=CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &psl);
+	if (hRes == S_OK)
+	{
+		hRes=psl->QueryInterface(IID_IPersistFile, (LPVOID*) &ppf);
+		if (hRes == S_OK)
+		{
+#ifdef UNICODE
+			hRes=ppf->Load(szBuf, STGM_READWRITE);
+#else
+      WCHAR* wszPath = (WCHAR*)LocalAlloc(LPTR, sizeof(WCHAR)*MAX_PATH);
+			MultiByteToWideChar(CP_ACP, 0, szBuf, -1, wszPath, MAX_PATH);
+			hRes=ppf->Load(wszPath, STGM_READWRITE);
+      LocalFree(wszPath);
+#endif
+			if (hRes == S_OK)
+			{
+				if (nType <= SHELLLINKTYPE_GETWORKINGDIR)
+				{
+					//Get
+					switch(nType)
+					{
+						case SHELLLINKTYPE_GETARGS:
+						{
+							hRes=psl->GetArguments(szBuf, MAX_PATH);
+							if (hRes != S_OK) szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETDESC: 
+						{
+							hRes=psl->GetDescription(szBuf, MAX_PATH);
+							if (hRes != S_OK) szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETHOTKEY: 
+						{
+							hRes=psl->GetHotkey(&wHotkey);
+							if (hRes == S_OK) wsprintf(szBuf, TEXT("%d"), wHotkey);
+							else szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETICONLOC: 
+						{
+							hRes=psl->GetIconLocation(szBuf, MAX_PATH, &nBuf);
+							if (hRes != S_OK) szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETICONINDEX: 
+						{
+							hRes=psl->GetIconLocation(szBuf, MAX_PATH, &nBuf);
+							if (hRes == S_OK) wsprintf(szBuf, TEXT("%d"), nBuf);
+							else szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETPATH: 
+						{
+							WIN32_FIND_DATA fd;
+
+							hRes=psl->GetPath(szBuf, MAX_PATH, &fd, SLGP_UNCPRIORITY);
+							if (hRes != S_OK) szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETSHOWMODE: 
+						{
+							hRes=psl->GetShowCmd(&nBuf);
+							if (hRes == S_OK) wsprintf(szBuf, TEXT("%d"), nBuf);
+							else szBuf[0]='\0';
+						}; break;
+						case SHELLLINKTYPE_GETWORKINGDIR:
+						{ 
+							hRes=psl->GetWorkingDirectory(szBuf, MAX_PATH);
+							if (hRes != S_OK) szBuf[0]='\0';
+						}; break;
+					}
+				}
+				else
+				{
+					//Set
+					switch(nType)
+					{
+						case SHELLLINKTYPE_SETARGS:
+						{
+							hRes=psl->SetArguments(szBuf2);
+						}; break;
+						case SHELLLINKTYPE_SETDESC: 
+						{
+							hRes=psl->SetDescription(szBuf2);
+						}; break;
+						case SHELLLINKTYPE_SETHOTKEY:
+						{
+							wHotkey=(unsigned short)myatoi(szBuf2);
+							hRes=psl->SetHotkey(wHotkey);
+						}; break;
+						case SHELLLINKTYPE_SETICONLOC:
+						{
+							hRes=psl->GetIconLocation(szBuf, MAX_PATH, &nBuf);
+							if (hRes == S_OK)
+								hRes=psl->SetIconLocation(szBuf2, nBuf);
+						}; break;
+						case SHELLLINKTYPE_SETICONINDEX: 
+						{
+							int nBuf2;
+							nBuf=myatoi(szBuf2);
+
+							hRes=psl->GetIconLocation(szBuf, MAX_PATH, &nBuf2);
+							if (hRes == S_OK)
+								hRes=psl->SetIconLocation(szBuf, nBuf);
+						}; break;
+						case SHELLLINKTYPE_SETPATH: 
+						{
+							hRes=psl->SetPath(szBuf2);
+						}; break;
+						case SHELLLINKTYPE_SETSHOWMODE: 
+						{
+							nBuf=myatoi(szBuf2);
+							hRes=psl->SetShowCmd(nBuf);
+						}; break;
+						case SHELLLINKTYPE_SETWORKINGDIR:
+						{
+							hRes=psl->SetWorkingDirectory(szBuf2);
+						}; break;
+						case SHELLLINKTYPE_SETRUNASADMIN:
+						{
+              IShellLinkDataList* pdl;
+              hRes=psl->QueryInterface(IID_IShellLinkDataList, (void**)&pdl);
+              if (hRes == S_OK)
+              {
+                DWORD dwFlags = 0;
+							  hRes=pdl->GetFlags(&dwFlags);
+                if (hRes == S_OK && (dwFlags & SLDF_RUNAS_USER) != SLDF_RUNAS_USER)
+                  hRes=pdl->SetFlags(dwFlags | SLDF_RUNAS_USER);
+                pdl->Release();
+              }
+						}; break;
+					}
+					if (hRes == S_OK) hRes=ppf->Save(NULL, FALSE);
+					#ifdef SHELLLINK_DEBUG
+					else MessageBox(hwndParent, TEXT("ERROR: Save()"), TEXT("ShellLink plug-in"), MB_OK);
+					#endif
+				}
+			}
+			#ifdef SHELLLINK_DEBUG
+			else MessageBox(hwndParent, TEXT("ERROR: Load()"), TEXT("ShellLink plug-in"), MB_OK);
+			#endif
+		}
+		#ifdef SHELLLINK_DEBUG
+		else MessageBox(hwndParent, TEXT("CShellLink::Initialise, Failed in call to QueryInterface for IPersistFile, HRESULT was %x\n"), TEXT("ShellLink plug-in"), MB_OK);
+		#endif
+
+		// Cleanup:
+		if (ppf) ppf->Release();
+		if (psl) psl->Release();
+	}
+	#ifdef SHELLLINK_DEBUG
+	else MessageBox(hwndParent, TEXT("ERROR: CoCreateInstance()"), TEXT("ShellLink plug-in"), MB_OK);
+	#endif
+
+	if (hRes == S_OK)
+	{
+		if (nType <= SHELLLINKTYPE_GETWORKINGDIR) pushstring(szBuf);
+		else pushstring(TEXT("0"));
+	}
+	else
+	{
+		if (nType <= SHELLLINKTYPE_GETWORKINGDIR) pushstring(TEXT(""));
+		else pushstring(TEXT("-1"));
+	}
+
+  LocalFree(szBuf);
+  LocalFree(szBuf2);
+}
+
+BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+{
+	return TRUE;
+}


=====================================
projects/nsis/build
=====================================
@@ -30,7 +30,8 @@ EOF
 chmod +x "$compiler_prefix-gcc"
 ln -s "$compiler_prefix-clang++" "$compiler_prefix-g++"
 
-cd /var/tmp/build/nsis-[% c('version') %]-src
+builddir=/var/tmp/build/nsis-[% c('version') %]-src
+cd "$builddir"
 
 # These two sed commands also come from build-mingw32-nsis.sh
 sed -i 's/-Wl,--exclude-libs,msvcrt.a/-Wl,-Xlink=-fixed/' SCons/Config/gnu
@@ -60,6 +61,22 @@ patch -p1 < "$rootdir/resource-reproducible.diff"
 scons [% scons_args %] -j[% c("num_procs") %] || true
 scons [% scons_args %]
 scons [% scons_args %] install
+
+# Plugins
+target="[% target %]-unicode"
+plugins="/var/tmp/dist/nsis/share/nsis/Plugins/$target"
+plugin_lib="$builddir/build/urelease/api/nsis/libpluginapi-$target.a"
+
+# This is not needed to build installers, but it makes easier to adapt plugins
+# outside our build system.
+mkdir /var/tmp/dist/nsis/share/nsis/Lib
+cp $plugin_lib /var/tmp/dist/nsis/share/nsis/Lib/
+
+$compiler_prefix-clang++ -I "$builddir/build/urelease/api" -O2 $plugin_lib \
+  -DUNICODE "$rootdir/ShellLink.cpp" \
+  -Wl,--no-insert-timestamp -lole32 -luuid -shared -o "$plugins/ShellLink.dll"
+llvm-strip "$plugins/ShellLink.dll"
+
 cd /var/tmp/dist
 [% c('tar', {
         tar_src => [ project ],


=====================================
projects/nsis/config
=====================================
@@ -24,3 +24,4 @@ input_files:
   - name: zlib
     project: zlib
   - filename: resource-reproducible.diff
+  - filename: ShellLink.cpp


=====================================
rbm.conf
=====================================
@@ -112,6 +112,8 @@ var:
   Project_Name_Channel: '[% c("var/Project_Name") %] [% c("var/channel") FILTER ucfirst %]'
   exe_name: firefox
   locale_ja: ja
+  # When adding new languages, add the equivalent NSIS name to
+  # projects/browser/windows-installer/language-map.sh.
   locales:
     - ar
     - ca



View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/compare/56df6e4ccd8a5d4be3ab48219b27c31ab07feeb9...8deb68f2e959fd1a914fda505ce10d35914f7d8d

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/compare/56df6e4ccd8a5d4be3ab48219b27c31ab07feeb9...8deb68f2e959fd1a914fda505ce10d35914f7d8d
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tbb-commits/attachments/20240213/cc0eca45/attachment-0001.htm>


More information about the tbb-commits mailing list