summaryrefslogtreecommitdiffstats
path: root/browser/installer/windows/nsis
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /browser/installer/windows/nsis
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/installer/windows/nsis')
-rw-r--r--browser/installer/windows/nsis/content/installing.html43
-rw-r--r--browser/installer/windows/nsis/content/installing.js58
-rw-r--r--browser/installer/windows/nsis/content/profile_cleanup.html42
-rw-r--r--browser/installer/windows/nsis/content/profile_cleanup.js30
-rw-r--r--browser/installer/windows/nsis/content/stub_common.css37
-rw-r--r--browser/installer/windows/nsis/content/stub_common.js23
-rw-r--r--browser/installer/windows/nsis/defines.nsi.in156
-rw-r--r--browser/installer/windows/nsis/extensionsLocale.nsh20
-rwxr-xr-xbrowser/installer/windows/nsis/installer.nsi2057
-rw-r--r--browser/installer/windows/nsis/maintenanceservice_installer.nsi343
-rwxr-xr-xbrowser/installer/windows/nsis/shared.nsh1808
-rw-r--r--browser/installer/windows/nsis/stub.nsi1772
-rwxr-xr-xbrowser/installer/windows/nsis/uninstaller.nsi1133
-rw-r--r--browser/installer/windows/nsis/updater_append.ini12
14 files changed, 7534 insertions, 0 deletions
diff --git a/browser/installer/windows/nsis/content/installing.html b/browser/installer/windows/nsis/content/installing.html
new file mode 100644
index 0000000000..e7b4450065
--- /dev/null
+++ b/browser/installer/windows/nsis/content/installing.html
@@ -0,0 +1,43 @@
+<!doctype html>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+<head>
+
+<meta charset="UTF-8">
+<meta http-equiv="X-UA-Compatible" content="IE=8">
+
+<link rel="stylesheet" href="stub_common.css">
+<link rel="stylesheet" href="installing_page.css">
+
+<script src="stub_common.js"></script>
+<script src="installing.js"></script>
+
+</head>
+<body>
+
+<img id="background" src="bgstub.jpg" alt="" role="presentation">
+
+<div id="text_column">
+ <div id="text_column_container">
+ <h1 id="header"></h1>
+ <div id="content"></div>
+ </div>
+</div>
+
+<div id="installing">
+ <div id="label" tabindex="0"></div>
+ <div id="progress_background">
+ <div id="progress_bar" role="progressbar" aria-labelledby="label" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" tabindex="0"></div>
+ </div>
+</div>
+
+<div id="blurb"></div>
+
+<div id="footer"></div>
+
+</body>
+</html>
diff --git a/browser/installer/windows/nsis/content/installing.js b/browser/installer/windows/nsis/content/installing.js
new file mode 100644
index 0000000000..869c76c324
--- /dev/null
+++ b/browser/installer/windows/nsis/content/installing.js
@@ -0,0 +1,58 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Length of time (milliseconds) that one blurb stays up before we switch to
+// displaying the next one.
+var BLURB_CYCLE_MS = 20000;
+
+// How frequently we should update the progress bar state, in milliseconds.
+var PROGRESS_BAR_INTERVAL_MS = 250;
+
+window.attachEvent("onload", function() {
+ // Set direction on the two components of the layout.
+ var direction = external.getTextDirection();
+ document.getElementById("text_column").style.direction = direction;
+ document.getElementById("installing").style.direction = direction;
+
+ // Get this page's static strings.
+ var label = document.getElementById("label");
+ label.innerText = external.getUIString("installing_label");
+ document.getElementById("header").innerText = external.getUIString(
+ "installing_header"
+ );
+ document.getElementById("content").innerText = external.getUIString(
+ "installing_content"
+ );
+
+ // Poll and update the progress bar percentage.
+ setInterval(function() {
+ var percent = external.getProgressBarPercent();
+ var progressBar = document.getElementById("progress_bar");
+ progressBar.setAttribute("aria-valuenow", percent);
+ progressBar.style.width = percent + "%";
+ }, PROGRESS_BAR_INTERVAL_MS);
+
+ // Get the blurb strings and initialize the blurb rotation.
+ var currentBlurb = 0;
+ // IE8 adds undefined to the array if there is a trailing comma in an
+ // array literal, so don't allow prettier to add one here.
+ // prettier-ignore
+ var blurbStrings = [
+ external.getUIString("installing_blurb_0"),
+ external.getUIString("installing_blurb_1"),
+ external.getUIString("installing_blurb_2")
+ ];
+ function rotateBlurb() {
+ document.getElementById("blurb").innerText = blurbStrings[currentBlurb];
+ currentBlurb = (currentBlurb + 1) % blurbStrings.length;
+ }
+ rotateBlurb();
+ setInterval(rotateBlurb, BLURB_CYCLE_MS);
+
+ // Focus the label, in order to get the focus in the web page, to
+ // assist screen readers. On Win 7's IE8 this causes the focus rectangle
+ // to be immediately visible, so also hide that here.
+ label.className += " no-focus-outline";
+ label.focus();
+});
diff --git a/browser/installer/windows/nsis/content/profile_cleanup.html b/browser/installer/windows/nsis/content/profile_cleanup.html
new file mode 100644
index 0000000000..4f20aaecba
--- /dev/null
+++ b/browser/installer/windows/nsis/content/profile_cleanup.html
@@ -0,0 +1,42 @@
+<!doctype html>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+<head>
+
+<meta charset="UTF-8">
+<meta http-equiv="X-UA-Compatible" content="IE=8">
+
+<link rel="stylesheet" href="stub_common.css">
+<link rel="stylesheet" href="profile_cleanup_page.css">
+
+<script src="stub_common.js"></script>
+<script src="profile_cleanup.js"></script>
+
+</head>
+<body>
+
+<img id="background" src="bgstub.jpg" alt="" role="presentation">
+
+<form id="profileRefreshForm">
+ <div id="profileRefreshContainer">
+ <h1 id="header"></h1>
+
+ <div id="refreshCheckboxContainer">
+ <input id="refreshCheckbox" type="checkbox" checked />
+ <label id="checkboxLabel" for="refreshCheckbox"></label>
+ </div>
+
+ <div id="refreshButtonContainer">
+ <button type="submit" id="refreshButton"></button>
+ </div>
+ </div>
+</form>
+
+<div id="footer"></div>
+
+</body>
+</html>
diff --git a/browser/installer/windows/nsis/content/profile_cleanup.js b/browser/installer/windows/nsis/content/profile_cleanup.js
new file mode 100644
index 0000000000..016b368b05
--- /dev/null
+++ b/browser/installer/windows/nsis/content/profile_cleanup.js
@@ -0,0 +1,30 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+window.attachEvent("onload", function() {
+ // Set text direction.
+ var direction = external.getTextDirection();
+ var profileRefreshForm = document.getElementById("profileRefreshForm");
+ profileRefreshForm.style.direction = direction;
+ var checkboxLabel = document.getElementById("checkboxLabel");
+ checkboxLabel.className += " checkboxLabel-" + direction;
+
+ // Get this page's static strings.
+ document.getElementById("header").innerText = external.getUIString(
+ "cleanup_header"
+ );
+ document.getElementById("refreshButton").innerText = external.getUIString(
+ "cleanup_button"
+ );
+ checkboxLabel.innerText = external.getUIString("cleanup_checkbox");
+
+ // Set up the confirmation button.
+ profileRefreshForm.attachEvent("onsubmit", function() {
+ var doProfileCleanup = document.getElementById("refreshCheckbox").checked;
+ external.gotoInstallPage(doProfileCleanup);
+ return false;
+ });
+
+ document.getElementById("refreshButton").focus();
+});
diff --git a/browser/installer/windows/nsis/content/stub_common.css b/browser/installer/windows/nsis/content/stub_common.css
new file mode 100644
index 0000000000..a8d15512b5
--- /dev/null
+++ b/browser/installer/windows/nsis/content/stub_common.css
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+body {
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+
+ font-family: "Segoe UI", sans-serif;
+}
+
+/* This is an <img> rather than using background-image because IE8
+ * does not support background-size. */
+#background {
+ min-height: 100%;
+ min-width: 100%;
+
+ width: 100%;
+ height: auto;
+
+ position: fixed;
+ top: 0;
+ left: 0;
+
+ z-index: -1;
+}
+
+body.high-contrast #background {
+ display: none;
+}
+
+.no-focus-outline {
+ outline: none;
+}
diff --git a/browser/installer/windows/nsis/content/stub_common.js b/browser/installer/windows/nsis/content/stub_common.js
new file mode 100644
index 0000000000..bcdf809b61
--- /dev/null
+++ b/browser/installer/windows/nsis/content/stub_common.js
@@ -0,0 +1,23 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+window.attachEvent("onload", function() {
+ if (parseInt(external.getIsHighContrast())) {
+ document.body.className += " high-contrast";
+ } else {
+ document.body.className += " normal-contrast";
+ }
+
+ document.body.style.fontFamily = external.getFontName() + ", sans-serif";
+
+ // All pages have the global footer (or don't, depending on the branding).
+ document.getElementById("footer").innerText = external.getUIString(
+ "global_footer"
+ );
+
+ // Disallow dragging of the "background" image.
+ document.getElementById("background").attachEvent("ondragstart", function() {
+ return false;
+ });
+});
diff --git a/browser/installer/windows/nsis/defines.nsi.in b/browser/installer/windows/nsis/defines.nsi.in
new file mode 100644
index 0000000000..fd39d599f5
--- /dev/null
+++ b/browser/installer/windows/nsis/defines.nsi.in
@@ -0,0 +1,156 @@
+#filter substitution
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Defining FunnelcakeVersion will append the value of StubURLVersionAppend to
+# StubURLVersion, append the value of URLManualDownloadAppend to
+# URLManualDownload, and append the value of URLStubDownloadAppend to
+# URLStubDownload. The value of FunnelcakeVersion should not be defined when it
+# is not used and when it is defined its value should never be empty.
+# !define FunnelcakeVersion "999"
+
+!ifdef FunnelcakeVersion
+!define URLManualDownloadAppend "&f=${FunnelcakeVersion}"
+!define URLStubDownloadAppend "-f${FunnelcakeVersion}"
+!define StubURLVersionAppend "-${FunnelcakeVersion}"
+!else
+!define URLManualDownloadAppend ""
+!define URLStubDownloadAppend ""
+!define StubURLVersionAppend ""
+!endif
+
+# These defines should match application.ini settings
+!define AppName "Firefox"
+!define AppVersion "@APP_VERSION@"
+!define GREVersion @MOZILLA_VERSION@
+!define AB_CD "@AB_CD@"
+
+!define FileMainEXE "@MOZ_APP_NAME@.exe"
+!define PrivateBrowsingEXE "private_browsing.exe"
+!define MainWindowClass "MozillaWindowClass"
+!define DialogWindowClass "MozillaDialogClass"
+!define DDEApplication "Firefox"
+!define AppRegName "Firefox"
+!define ToastAumidPrefix "@MOZ_TOAST_APP_NAME@Toast-"
+
+!define BrandProductName "Firefox"
+!ifndef DEV_EDITION
+!define BrandShortName "@MOZ_APP_DISPLAYNAME@"
+!endif
+!ifndef BrandFullName
+!define BrandFullName "${BrandFullNameInternal}"
+!endif
+
+; The C++ defines in `nsNativeAppSupportWin.h` are 1-based. The Windows
+; resource IDs in the registry are 0-based.
+!define IDI_APPICON_ZERO_BASED "0"
+!define IDI_DOCUMENT_ZERO_BASED "1"
+!define IDI_PBICON_ZERO_BASED "4"
+!define IDI_DOCUMENT_PDF_ZERO_BASED "5"
+
+; This one is the location of the Private Browsing icon in
+; private_browsing.exe (as opposed to @MOZ_APP_NAME@.exe)
+!define IDI_PBICON_PB_EXE_ZERO_BASED "0"
+
+!define CERTIFICATE_NAME "Mozilla Corporation"
+!define CERTIFICATE_ISSUER "DigiCert SHA2 Assured ID Code Signing CA"
+; Changing the name or issuer requires us to have both the old and the new
+; in the registry at the same time, temporarily.
+!define CERTIFICATE_NAME_PREVIOUS "Mozilla Corporation"
+!define CERTIFICATE_ISSUER_PREVIOUS "DigiCert Assured ID Code Signing CA-1"
+
+# LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP
+# category value is ANDed together to set multiple permitted categories.
+# See http://msdn.microsoft.com/en-us/library/ms742253%28VS.85%29.aspx
+# The value below removes all LSP categories previously set.
+!define LSP_CATEGORIES "0x00000000"
+
+!if "@MOZ_UPDATE_CHANNEL@" == ""
+!define UpdateChannel "Unknown"
+!else
+!define UpdateChannel "@MOZ_UPDATE_CHANNEL@"
+!endif
+
+!define AccessibleHandlerCLSID "@MOZ_HANDLER_CLSID@"
+
+#ifdef MOZ_LAUNCHER_PROCESS
+!define MOZ_LAUNCHER_PROCESS
+!define MOZ_LAUNCHER_SUBKEY "Software\Mozilla\${AppName}\Launcher"
+#endif
+
+#ifdef RELEASE_OR_BETA
+!define RELEASE_OR_BETA
+#endif
+
+# Due to official and beta using the same branding this is needed to
+# differentiante between the url used by the stub for downloading.
+!if "@MOZ_UPDATE_CHANNEL@" == "beta"
+!define BETA_UPDATE_CHANNEL
+!endif
+
+!define BaseURLStubPing "http://download-stats.mozilla.org/stub"
+
+# ARCH is used when it is necessary to differentiate the x64 registry keys from
+# the x86 registry keys (e.g. the uninstall registry key).
+#ifdef HAVE_64BIT_BUILD
+!define HAVE_64BIT_BUILD
+#ifdef _ARM64_
+!define ARCH "AArch64"
+!define MinSupportedVer "Microsoft Windows 10 for ARM"
+#else
+!define ARCH "x64"
+!define MinSupportedVer "Microsoft Windows 7 x64"
+#endif
+#else
+!define MinSupportedVer "Microsoft Windows 7"
+!define ARCH "x86"
+#endif
+
+!define MinSupportedCPU "SSE2"
+
+#ifdef MOZ_MAINTENANCE_SERVICE
+!define MOZ_MAINTENANCE_SERVICE
+#endif
+
+#ifdef MOZ_BITS_DOWNLOAD
+!define MOZ_BITS_DOWNLOAD
+#endif
+
+#ifdef MOZ_DEFAULT_BROWSER_AGENT
+!define MOZ_DEFAULT_BROWSER_AGENT
+#endif
+
+!if "@AB_CD@" == "en-US"
+!define MOZ_OPTIONAL_EXTENSIONS
+!else if "@AB_CD@" == "zh-CN"
+!define MOZ_OPTIONAL_EXTENSIONS
+!endif
+
+# To add Private Browsing shortcut argument to setup.exe
+!define MOZ_PRIVATE_BROWSING
+
+# File details shared by both the installer and uninstaller
+VIProductVersion "1.0.0.0"
+VIAddVersionKey "ProductName" "${BrandShortName}"
+VIAddVersionKey "CompanyName" "${CompanyName}"
+VIAddVersionKey "LegalCopyright" "${CompanyName}"
+VIAddVersionKey "FileVersion" "${AppVersion}"
+VIAddVersionKey "ProductVersion" "${AppVersion}"
+# Comments is not used but left below commented out for future reference
+# VIAddVersionKey "Comments" "Comments"
+
+# It isn't possible to get the size of the installation prior to downloading
+# so the stub installer uses an estimate. The size is derived from the size of
+# the complete installer, the size of the extracted complete installer, and at
+# least 15 MB additional for working room.
+!define APPROXIMATE_REQUIRED_SPACE_MB "145"
+
+# Constants for parts of the telemetry submission URL
+!define TELEMETRY_BASE_URL https://incoming.telemetry.mozilla.org/submit
+!define TELEMETRY_NAMESPACE firefox-installer
+!define TELEMETRY_INSTALL_PING_VERSION 1
+!define TELEMETRY_INSTALL_PING_DOCTYPE install
+
+!define TELEMETRY_UNINSTALL_PING_NAMESPACE telemetry
+!define TELEMETRY_UNINSTALL_PING_DOCTYPE uninstall
diff --git a/browser/installer/windows/nsis/extensionsLocale.nsh b/browser/installer/windows/nsis/extensionsLocale.nsh
new file mode 100644
index 0000000000..5a24373bd0
--- /dev/null
+++ b/browser/installer/windows/nsis/extensionsLocale.nsh
@@ -0,0 +1,20 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+; Strings for the optional extensions page. This is not in the locale
+; directory so these strings are only translated to zh-CN.
+
+!if "${AB_CD}" == "en-US"
+LangString EXTENSIONS_PAGE_TITLE 0 "Install Optional Extensions"
+LangString EXTENSIONS_PAGE_SUBTITLE 0 "$ExtensionRecommender recommends these extensions"
+LangString OPTIONAL_EXTENSIONS_CHECKBOX_DESC 0 "Install &Extension:"
+LangString OPTIONAL_EXTENSIONS_DESC 0 "You can add or remove these extensions at any time. Click the menu button and choose “Add-ons”."
+!endif
+
+!if "${AB_CD}" == "zh-CN"
+LangString EXTENSIONS_PAGE_TITLE 0 "安装可选扩展"
+LangString EXTENSIONS_PAGE_SUBTITLE 0 "$ExtensionRecommender 推荐安装以下扩展"
+LangString OPTIONAL_EXTENSIONS_CHECKBOX_DESC 0 "安装扩展(&E):"
+LangString OPTIONAL_EXTENSIONS_DESC 0 "您随时可以点击浏览器的菜单按钮并选择“附加组件”来添加或移除扩展。"
+!endif \ No newline at end of file
diff --git a/browser/installer/windows/nsis/installer.nsi b/browser/installer/windows/nsis/installer.nsi
new file mode 100755
index 0000000000..40386f8915
--- /dev/null
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -0,0 +1,2057 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Required Plugins:
+# AppAssocReg
+# http://nsis.sourceforge.net/Application_Association_Registration_plug-in
+# ApplicationID
+# http://nsis.sourceforge.net/ApplicationID_plug-in
+# CityHash
+# http://searchfox.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
+# nsJSON
+# http://nsis.sourceforge.net/NsJSON_plug-in
+# ShellLink
+# http://nsis.sourceforge.net/ShellLink_plug-in
+# UAC
+# http://nsis.sourceforge.net/UAC_plug-in
+# ServicesHelper
+# Mozilla specific plugin that is located in /other-licenses/nsis
+
+; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
+!verbose 3
+
+; 7-Zip provides better compression than the lzma from NSIS so we add the files
+; uncompressed and use 7-Zip to create a SFX archive of it
+SetDatablockOptimize on
+SetCompress off
+CRCCheck on
+
+RequestExecutionLevel user
+
+Unicode true
+ManifestSupportedOS all
+ManifestDPIAware true
+
+!addplugindir ./
+
+Var TmpVal
+Var InstallType
+Var AddStartMenuSC
+Var AddTaskbarSC
+Var AddQuickLaunchSC
+Var AddDesktopSC
+Var AddPrivateBrowsingSC
+Var InstallMaintenanceService
+Var InstallOptionalExtensions
+Var ExtensionRecommender
+Var PageName
+Var PreventRebootRequired
+Var RegisterDefaultAgent
+
+; Telemetry ping fields
+Var SetAsDefault
+Var HadOldInstall
+Var InstallExisted
+Var DefaultInstDir
+Var IntroPhaseStart
+Var OptionsPhaseStart
+Var InstallPhaseStart
+Var FinishPhaseStart
+Var FinishPhaseEnd
+Var InstallResult
+Var LaunchedNewApp
+Var PostSigningData
+
+; By defining NO_STARTMENU_DIR an installer that doesn't provide an option for
+; an application's Start Menu PROGRAMS directory and doesn't define the
+; StartMenuDir variable can use the common InstallOnInitCommon macro.
+!define NO_STARTMENU_DIR
+
+; Attempt to elevate Standard Users in addition to users that
+; are a member of the Administrators group.
+!define NONADMIN_ELEVATE
+
+!define AbortSurveyURL "http://www.kampyle.com/feedback_form/ff-feedback-form.php?site_code=8166124&form_id=12116&url="
+
+; Other included files may depend upon these includes!
+; The following includes are provided by NSIS.
+!include FileFunc.nsh
+!include LogicLib.nsh
+!include MUI.nsh
+!include WinMessages.nsh
+!include WinVer.nsh
+!include WordFunc.nsh
+
+!insertmacro GetOptions
+!insertmacro GetParameters
+!insertmacro GetSize
+!insertmacro StrFilter
+!insertmacro WordFind
+!insertmacro WordReplace
+
+; The following includes are custom.
+!include branding.nsi
+!include defines.nsi
+!include common.nsh
+!include locales.nsi
+
+VIAddVersionKey "FileDescription" "${BrandShortName} Installer"
+VIAddVersionKey "OriginalFilename" "setup.exe"
+
+; Must be inserted before other macros that use logging
+!insertmacro _LoggingCommon
+
+!insertmacro AddDisabledDDEHandlerValues
+!insertmacro ChangeMUIHeaderImage
+!insertmacro ChangeMUISidebarImage
+!insertmacro CheckForFilesInUse
+!insertmacro CleanUpdateDirectories
+!insertmacro CopyFilesFromDir
+!insertmacro CopyPostSigningData
+!insertmacro CreateRegKey
+!insertmacro GetFirstInstallPath
+!insertmacro GetLongPath
+!insertmacro GetPathFromString
+!insertmacro GetParent
+!insertmacro InitHashAppModelId
+!insertmacro IsHandlerForInstallDir
+!insertmacro IsPinnedToTaskBar
+!insertmacro IsUserAdmin
+!insertmacro LogDesktopShortcut
+!insertmacro LogQuickLaunchShortcut
+!insertmacro LogStartMenuShortcut
+!insertmacro ManualCloseAppPrompt
+!insertmacro PinnedToStartMenuLnkCount
+!insertmacro RegCleanAppHandler
+!insertmacro RegCleanMain
+!insertmacro RegCleanUninstall
+!insertmacro RemovePrecompleteEntries
+!insertmacro SetAppLSPCategories
+!insertmacro SetBrandNameVars
+!insertmacro UpdateShortcutAppModelIDs
+!insertmacro UnloadUAC
+!insertmacro WriteRegStr2
+!insertmacro WriteRegDWORD2
+
+; This needs to be inserted after InitHashAppModelId because it uses
+; $AppUserModelID and the compiler can't handle using variables lexically before
+; they've been declared.
+!insertmacro GetInstallerRegistryPref
+
+!include shared.nsh
+
+; Helper macros for ui callbacks. Insert these after shared.nsh
+!insertmacro CheckCustomCommon
+!insertmacro InstallEndCleanupCommon
+!insertmacro InstallOnInitCommon
+!insertmacro InstallStartCleanupCommon
+!insertmacro LeaveDirectoryCommon
+!insertmacro LeaveOptionsCommon
+!insertmacro OnEndCommon
+!insertmacro PreDirectoryCommon
+
+Name "${BrandFullName}"
+OutFile "setup.exe"
+!ifdef HAVE_64BIT_BUILD
+ InstallDir "$PROGRAMFILES64\${BrandFullName}\"
+!else
+ InstallDir "$PROGRAMFILES32\${BrandFullName}\"
+!endif
+ShowInstDetails nevershow
+
+################################################################################
+# Modern User Interface - MUI
+
+!define MOZ_MUI_CUSTOM_ABORT
+!define MUI_CUSTOMFUNCTION_ABORT "CustomAbort"
+!define MUI_ICON setup.ico
+!define MUI_UNICON setup.ico
+!define MUI_WELCOMEPAGE_TITLE_3LINES
+!define MUI_HEADERIMAGE
+!define MUI_HEADERIMAGE_RIGHT
+!define MUI_WELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
+; By default MUI_BGCOLOR is hardcoded to FFFFFF, which is only correct if the
+; Windows theme or high-contrast mode hasn't changed it, so we need to
+; override that with GetSysColor(COLOR_WINDOW) (this string ends up getting
+; passed to SetCtlColors, which uses this custom syntax to mean that).
+!define MUI_BGCOLOR SYSCLR:WINDOW
+
+; Use a right to left header image when the language is right to left
+!ifdef ${AB_CD}_rtl
+!define MUI_HEADERIMAGE_BITMAP_RTL wizHeaderRTL.bmp
+!else
+!define MUI_HEADERIMAGE_BITMAP wizHeader.bmp
+!endif
+
+/**
+ * Installation Pages
+ */
+; Welcome Page
+!define MUI_PAGE_CUSTOMFUNCTION_PRE preWelcome
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW showWelcome
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE leaveWelcome
+!insertmacro MUI_PAGE_WELCOME
+
+; Custom Options Page
+Page custom preOptions leaveOptions
+
+; Select Install Directory Page
+!define MUI_PAGE_CUSTOMFUNCTION_PRE preDirectory
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE leaveDirectory
+!define MUI_DIRECTORYPAGE_VERIFYONLEAVE
+!insertmacro MUI_PAGE_DIRECTORY
+
+; Custom Components Page
+!ifdef MOZ_MAINTENANCE_SERVICE
+Page custom preComponents leaveComponents
+!endif
+
+; Custom Shortcuts Page
+Page custom preShortcuts leaveShortcuts
+
+; Custom Extensions Page
+!ifdef MOZ_OPTIONAL_EXTENSIONS
+Page custom preExtensions leaveExtensions
+!endif
+
+; Custom Summary Page
+Page custom preSummary leaveSummary
+
+; Install Files Page
+!insertmacro MUI_PAGE_INSTFILES
+
+; Finish Page
+!define MUI_FINISHPAGE_TITLE_3LINES
+!define MUI_FINISHPAGE_RUN
+!define MUI_FINISHPAGE_RUN_FUNCTION LaunchApp
+!define MUI_FINISHPAGE_RUN_TEXT $(LAUNCH_TEXT)
+!define MUI_PAGE_CUSTOMFUNCTION_PRE preFinish
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW showFinish
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE postFinish
+!insertmacro MUI_PAGE_FINISH
+
+; Use the default dialog for IDD_VERIFY for a simple Banner
+ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe"
+
+################################################################################
+# Install Sections
+
+; Cleanup operations to perform at the start of the installation.
+Section "-InstallStartCleanup"
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $InstallPhaseStart
+
+ SetDetailsPrint both
+ DetailPrint $(STATUS_CLEANUP)
+ SetDetailsPrint none
+
+ SetOutPath "$INSTDIR"
+ ${StartInstallLog} "${BrandFullName}" "${AB_CD}" "${AppVersion}" "${GREVersion}"
+
+ StrCpy $R9 "true"
+ StrCpy $PreventRebootRequired "false"
+ ${GetParameters} $R8
+ ${GetOptions} "$R8" "/INI=" $R7
+ ${Unless} ${Errors}
+ ; The configuration file must also exist
+ ${If} ${FileExists} "$R7"
+ ReadINIStr $R9 $R7 "Install" "RemoveDistributionDir"
+ ReadINIStr $R8 $R7 "Install" "PreventRebootRequired"
+ ${If} $R8 == "true"
+ StrCpy $PreventRebootRequired "true"
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+
+ ${GetParameters} $R8
+ ${InstallGetOption} $R8 "RemoveDistributionDir" $R9
+ ${If} $R9 == "0"
+ StrCpy $R9 "false"
+ ${EndIf}
+ ${InstallGetOption} $R8 "PreventRebootRequired" $PreventRebootRequired
+ ${If} $PreventRebootRequired == "1"
+ StrCpy $PreventRebootRequired "true"
+ ${EndIf}
+
+ ; Remove directories and files we always control before parsing the uninstall
+ ; log so empty directories can be removed.
+ ${If} ${FileExists} "$INSTDIR\updates"
+ RmDir /r "$INSTDIR\updates"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\updated"
+ RmDir /r "$INSTDIR\updated"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\defaults\shortcuts"
+ RmDir /r "$INSTDIR\defaults\shortcuts"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\distribution"
+ ${AndIf} $R9 != "false"
+ RmDir /r "$INSTDIR\distribution"
+ ${EndIf}
+
+ Call CheckIfInstallExisted
+
+ ; Delete the app exe if present to prevent launching the app while we are
+ ; installing.
+ ClearErrors
+ ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+ ${If} ${Errors}
+ ; If the user closed the application it can take several seconds for it to
+ ; shut down completely. If the application is being used by another user we
+ ; can rename the file and then delete is when the system is restarted.
+ Sleep 5000
+ ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+ ClearErrors
+ ${EndIf}
+
+ ; setup the application model id registration value
+ ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
+
+ ; Remove the updates directory
+ ${CleanUpdateDirectories} "Mozilla\Firefox" "Mozilla\updates"
+
+ ${RemoveDeprecatedFiles}
+ ${RemovePrecompleteEntries} "false"
+
+ ${If} ${FileExists} "$INSTDIR\defaults\pref\channel-prefs.js"
+ Delete "$INSTDIR\defaults\pref\channel-prefs.js"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\defaults\pref"
+ RmDir "$INSTDIR\defaults\pref"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\defaults"
+ RmDir "$INSTDIR\defaults"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\uninstall"
+ ; Remove the uninstall directory that we control
+ RmDir /r "$INSTDIR\uninstall"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\update-settings.ini"
+ Delete "$INSTDIR\update-settings.ini"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\installation_telemetry.json"
+ Delete "$INSTDIR\installation_telemetry.json"
+ ${EndIf}
+
+ ; Explictly remove empty webapprt dir in case it exists (bug 757978).
+ RmDir "$INSTDIR\webapprt\components"
+ RmDir "$INSTDIR\webapprt"
+
+ ${InstallStartCleanupCommon}
+SectionEnd
+
+Section "-Application" APP_IDX
+ ${StartUninstallLog}
+
+ SetDetailsPrint both
+ DetailPrint $(STATUS_INSTALL_APP)
+ SetDetailsPrint none
+
+ ${LogHeader} "Installing Main Files"
+ ${CopyFilesFromDir} "$EXEDIR\core" "$INSTDIR" \
+ "$(ERROR_CREATE_DIRECTORY_PREFIX)" \
+ "$(ERROR_CREATE_DIRECTORY_SUFFIX)"
+
+ ; Register DLLs
+ ; XXXrstrong - AccessibleMarshal.dll can be used by multiple applications but
+ ; is only registered for the last application installed. When the last
+ ; application installed is uninstalled AccessibleMarshal.dll will no longer be
+ ; registered. bug 338878
+ ${LogHeader} "DLL Registration"
+ ClearErrors
+ ${RegisterDLL} "$INSTDIR\AccessibleMarshal.dll"
+ ${If} ${Errors}
+ ${LogMsg} "** ERROR Registering: $INSTDIR\AccessibleMarshal.dll **"
+ ${Else}
+ ${LogUninstall} "DLLReg: \AccessibleMarshal.dll"
+ ${LogMsg} "Registered: $INSTDIR\AccessibleMarshal.dll"
+ ${EndIf}
+
+ ClearErrors
+
+ ${RegisterDLL} "$INSTDIR\AccessibleHandler.dll"
+ ${If} ${Errors}
+ ${LogMsg} "** ERROR Registering: $INSTDIR\AccessibleHandler.dll **"
+ ${Else}
+ ${LogUninstall} "DLLReg: \AccessibleHandler.dll"
+ ${LogMsg} "Registered: $INSTDIR\AccessibleHandler.dll"
+ ${EndIf}
+
+ ClearErrors
+
+ ; Record the Windows Error Reporting module
+ WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\RuntimeExceptionHelperModules" "$INSTDIR\mozwer.dll" 0
+ ${If} ${Errors}
+ ${LogMsg} "** ERROR Recording: $INSTDIR\mozwer.dll **"
+ ${Else}
+ ${LogMsg} "Recorded: $INSTDIR\mozwer.dll"
+ ${EndIf}
+
+ ClearErrors
+
+ ; Default for creating Start Menu shortcut
+ ; (1 = create, 0 = don't create)
+ ${If} $AddStartMenuSC == ""
+ StrCpy $AddStartMenuSC "1"
+ ${EndIf}
+
+ ${If} $AddPrivateBrowsingSC == ""
+ StrCpy $AddPrivateBrowsingSC "1"
+ ${EndIf}
+
+ ; Default for creating Quick Launch shortcut (1 = create, 0 = don't create)
+ ${If} $AddQuickLaunchSC == ""
+ ; Don't install the quick launch shortcut on Windows 7
+ ${If} ${AtLeastWin7}
+ StrCpy $AddQuickLaunchSC "0"
+ ${Else}
+ StrCpy $AddQuickLaunchSC "1"
+ ${EndIf}
+ ${EndIf}
+
+ ; Default for creating Desktop shortcut (1 = create, 0 = don't create)
+ ${If} $AddDesktopSC == ""
+ StrCpy $AddDesktopSC "1"
+ ${EndIf}
+
+ ; Default for adding a Taskbar pin (1 = pin, 0 = don't pin)
+ ${If} $AddTaskbarSC == ""
+ StrCpy $AddTaskbarSC "1"
+ ${EndIf}
+
+ ${LogHeader} "Adding Registry Entries"
+ SetShellVarContext current ; Set SHCTX to HKCU
+ ${RegCleanMain} "Software\Mozilla"
+ ${RegCleanUninstall}
+ ${UpdateProtocolHandlers}
+
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
+ ${If} ${Errors}
+ StrCpy $TmpVal "HKCU" ; used primarily for logging
+ ${Else}
+ SetShellVarContext all ; Set SHCTX to HKLM
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ StrCpy $TmpVal "HKLM" ; used primarily for logging
+ ${RegCleanMain} "Software\Mozilla"
+ ${RegCleanUninstall}
+ ${UpdateProtocolHandlers}
+
+ ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
+ ${If} "$0" != "${GREVersion}"
+ WriteRegStr HKLM "Software\mozilla.org\Mozilla" "CurrentVersion" "${GREVersion}"
+ ${EndIf}
+ ${EndIf}
+
+ ${RemoveDeprecatedKeys}
+ ${Set32to64DidMigrateReg}
+
+ ; The previous installer adds several regsitry values to both HKLM and HKCU.
+ ; We now try to add to HKLM and if that fails to HKCU
+
+ ; The order that reg keys and values are added is important if you use the
+ ; uninstall log to remove them on uninstall. When using the uninstall log you
+ ; MUST add children first so they will be removed first on uninstall so they
+ ; will be empty when the key is deleted. This allows the uninstaller to
+ ; specify that only empty keys will be deleted.
+ ${SetAppKeys}
+
+ ${FixClassKeys}
+
+ ; Uninstall keys can only exist under HKLM on some versions of windows. Since
+ ; it doesn't cause problems always add them.
+ ${SetUninstallKeys}
+
+ ; On install always add the FirefoxHTML-, FirefoxPDF-, and FirefoxURL- keys.
+ ; An empty string is used for the 5th param because FirefoxHTML- is not a
+ ; protocol handler.
+ ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
+ StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
+
+ ; In Win8, the delegate execute handler picks up the value in FirefoxURL- and
+ ; FirefoxHTML- to launch the desktop browser when it needs to.
+ ${AddDisabledDDEHandlerValues} "FirefoxHTML-$AppUserModelID" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} HTML Document" ""
+ ${AddDisabledDDEHandlerValues} "FirefoxPDF-$AppUserModelID" "$2" "$8,${IDI_DOCUMENT_PDF_ZERO_BASED}" \
+ "${AppRegName} PDF Document" ""
+ ${AddDisabledDDEHandlerValues} "FirefoxURL-$AppUserModelID" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} URL" "true"
+
+ ; For pre win8, the following keys should only be set if we can write to HKLM.
+ ; For post win8, the keys below can be set in HKCU if needed.
+ ${If} $TmpVal == "HKLM"
+ ; Set the Start Menu Internet and Registered App HKLM registry keys.
+ ${SetStartMenuInternet} "HKLM"
+ ${FixShellIconHandler} "HKLM"
+ ${ElseIf} ${AtLeastWin8}
+ ; Set the Start Menu Internet and Registered App HKCU registry keys.
+ ${SetStartMenuInternet} "HKCU"
+ ${FixShellIconHandler} "HKCU"
+ ${EndIf}
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+ ; If the maintenance service page was displayed then a value was already
+ ; explicitly selected for installing the maintenance service and
+ ; and so InstallMaintenanceService will already be 0 or 1.
+ ; If the maintenance service page was not displayed then
+ ; InstallMaintenanceService will be equal to "".
+ ${If} $InstallMaintenanceService == ""
+ Call IsUserAdmin
+ Pop $R0
+ ${If} $R0 == "true"
+ ; Only proceed if we have HKLM write access
+ ${AndIf} $TmpVal == "HKLM"
+ ; The user is an admin, so we should default to installing the service.
+ StrCpy $InstallMaintenanceService "1"
+ ${Else}
+ ; The user is not admin, so we can't install the service.
+ StrCpy $InstallMaintenanceService "0"
+ ${EndIf}
+ ${EndIf}
+
+ ${If} $InstallMaintenanceService == "1"
+ ; The user wants to install the maintenance service, so execute
+ ; the pre-packaged maintenance service installer.
+ ; This option can only be turned on if the user is an admin so there
+ ; is no need to use ExecShell w/ verb runas to enforce elevated.
+ nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""
+ ${EndIf}
+!endif
+
+ ; These need special handling on uninstall since they may be overwritten by
+ ; an install into a different location.
+ StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}"
+ ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0
+ ${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0
+
+ StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\$R9"
+ ${CreateRegKey} "$TmpVal" "$0" 0
+ StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\plugin-container.exe"
+ ${CreateRegKey} "$TmpVal" "$0" 0
+
+ ${If} $TmpVal == "HKLM"
+ ; Set the permitted LSP Categories
+ ${SetAppLSPCategories} ${LSP_CATEGORIES}
+ ${EndIf}
+
+!ifdef MOZ_LAUNCHER_PROCESS
+ ; Launcher telemetry is opt-out, so we always enable it by default in new
+ ; installs. We always use HKCU because this value is a reflection of a pref
+ ; from the user profile. While this is not a perfect abstraction (given the
+ ; possibility of multiple Firefox profiles owned by the same Windows user), it
+ ; is more accurate than a machine-wide setting, and should be accurate in the
+ ; majority of cases.
+ WriteRegDWORD HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Telemetry" 1
+!endif
+
+ ${If} ${AtLeastWin10}
+ ${WriteToastNotificationRegistration} $TmpVal
+ ${EndIf}
+
+ ; Create shortcuts
+ ${LogHeader} "Adding Shortcuts"
+
+ ; Remove the start menu shortcuts and directory if the SMPROGRAMS section
+ ; exists in the shortcuts_log.ini and the SMPROGRAMS. The installer's shortcut
+ ; creation code will create the shortcut in the root of the Start Menu
+ ; Programs directory.
+ ${RemoveStartMenuDir}
+
+ ; Always add the application's shortcuts to the shortcuts log ini file. The
+ ; DeleteShortcuts macro will do the right thing on uninstall if the
+ ; shortcuts don't exist.
+ ${LogStartMenuShortcut} "${BrandShortName}.lnk"
+ ${LogQuickLaunchShortcut} "${BrandShortName}.lnk"
+ ${LogDesktopShortcut} "${BrandShortName}.lnk"
+
+ ; Best effort to update the Win7 taskbar and start menu shortcut app model
+ ; id's. The possible contexts are current user / system and the user that
+ ; elevated the installer.
+ Call FixShortcutAppModelIDs
+ ; If the current context is all also perform Win7 taskbar and start menu link
+ ; maintenance for the current user context.
+ ${If} $TmpVal == "HKLM"
+ SetShellVarContext current ; Set SHCTX to HKCU
+ Call FixShortcutAppModelIDs
+ SetShellVarContext all ; Set SHCTX to HKLM
+ ${EndIf}
+
+ ; If running elevated also perform Win7 taskbar and start menu link
+ ; maintenance for the unelevated user context in case that is different than
+ ; the current user.
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $0
+ ${Unless} ${Errors}
+ GetFunctionAddress $0 FixShortcutAppModelIDs
+ UAC::ExecCodeSegment $0
+ ${EndUnless}
+
+ ; UAC only allows elevating to an Admin account so there is no need to add
+ ; the Start Menu or Desktop shortcuts from the original unelevated process
+ ; since this will either add it for the user if unelevated or All Users if
+ ; elevated.
+ ${If} $AddStartMenuSC == 1
+ ; See if there's an existing shortcut for this installation using the old
+ ; name that we should just rename, instead of creating a new shortcut.
+ ; We could do this renaming even when $AddStartMenuSC is false; the idea
+ ; behind not doing that is to interpret "false" as "don't do anything
+ ; involving start menu shortcuts at all." We could also try to do this for
+ ; both shell contexts, but that won't typically accomplish anything.
+ ${If} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk"
+ ShellLink::GetShortCutTarget "$SMPROGRAMS\${BrandFullName}.lnk"
+ Pop $0
+ ${GetLongPath} "$0" $0
+ ${If} $0 == "$INSTDIR\${FileMainEXE}"
+ ${AndIfNot} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ Rename "$SMPROGRAMS\${BrandFullName}.lnk" \
+ "$SMPROGRAMS\${BrandShortName}.lnk"
+ ${LogMsg} "Renamed existing shortcut to $SMPROGRAMS\${BrandShortName}.lnk"
+ ${EndIf}
+ ${Else}
+ CreateShortCut "$SMPROGRAMS\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$SMPROGRAMS\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${If} "$AppUserModelID" != ""
+ ApplicationID::Set "$SMPROGRAMS\${BrandShortName}.lnk" \
+ "$AppUserModelID" "true"
+ ${EndIf}
+ ${LogMsg} "Added Shortcut: $SMPROGRAMS\${BrandShortName}.lnk"
+ ${Else}
+ ${LogMsg} "** ERROR Adding Shortcut: $SMPROGRAMS\${BrandShortName}.lnk"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+ ; This is always added if it doesn't already exist to ensure that Windows'
+ ; native "Pin to Taskbar" functionality can find an appropriate shortcut.
+ ; See https://bugzilla.mozilla.org/show_bug.cgi?id=1762994 for additional
+ ; background.
+ ${If} $AddPrivateBrowsingSC == 1
+ ${AddPrivateBrowsingShortcut}
+ ${EndIf}
+
+ ; Update lastwritetime of the Start Menu shortcut to clear the tile cache.
+ ; Do this for both shell contexts in case the user has shortcuts in multiple
+ ; locations, then restore the previous context at the end.
+ ${If} ${AtLeastWin8}
+ SetShellVarContext all
+ ${TouchStartMenuShortcut}
+ SetShellVarContext current
+ ${TouchStartMenuShortcut}
+ ${If} $TmpVal == "HKLM"
+ SetShellVarContext all
+ ${ElseIf} $TmpVal == "HKCU"
+ SetShellVarContext current
+ ${EndIf}
+ ${EndIf}
+
+ ${If} $AddDesktopSC == 1
+ ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk"
+ ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk"
+ Pop $0
+ ${GetLongPath} "$0" $0
+ ${If} $0 == "$INSTDIR\${FileMainEXE}"
+ ${AndIfNot} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ Rename "$DESKTOP\${BrandFullName}.lnk" "$DESKTOP\${BrandShortName}.lnk"
+ ${LogMsg} "Renamed existing shortcut to $DESKTOP\${BrandShortName}.lnk"
+ ${EndIf}
+ ${Else}
+ CreateShortCut "$DESKTOP\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${If} "$AppUserModelID" != ""
+ ApplicationID::Set "$DESKTOP\${BrandShortName}.lnk" \
+ "$AppUserModelID" "true"
+ ${EndIf}
+ ${LogMsg} "Added Shortcut: $DESKTOP\${BrandShortName}.lnk"
+ ${Else}
+ ${LogMsg} "** ERROR Adding Shortcut: $DESKTOP\${BrandShortName}.lnk"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+ ; If elevated the Quick Launch shortcut must be added from the unelevated
+ ; original process.
+ ${If} $AddQuickLaunchSC == 1
+ ${Unless} ${AtLeastWin7}
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $0
+ ${If} ${Errors}
+ Call AddQuickLaunchShortcut
+ ${LogMsg} "Added Shortcut: $QUICKLAUNCH\${BrandShortName}.lnk"
+ ${Else}
+ ; It is not possible to add a log entry from the unelevated process so
+ ; add the log entry without the path since there is no simple way to
+ ; know the correct full path.
+ ${LogMsg} "Added Quick Launch Shortcut: ${BrandShortName}.lnk"
+ GetFunctionAddress $0 AddQuickLaunchShortcut
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+ ${EndUnless}
+ ${EndIf}
+
+!ifdef MOZ_OPTIONAL_EXTENSIONS
+ ${If} ${FileExists} "$INSTDIR\distribution\optional-extensions"
+ ${LogHeader} "Installing optional extensions if requested"
+
+ ${If} $InstallOptionalExtensions != "0"
+ ${AndIf} ${FileExists} "$INSTDIR\distribution\setup.ini"
+ ${Unless} ${FileExists} "$INSTDIR\distribution\extensions"
+ CreateDirectory "$INSTDIR\distribution\extensions"
+ ${EndUnless}
+
+ StrCpy $0 0
+ ${Do}
+ ClearErrors
+ ReadINIStr $1 "$INSTDIR\distribution\setup.ini" "OptionalExtensions" \
+ "extension.$0.id"
+ ${If} ${Errors}
+ ${ExitDo}
+ ${EndIf}
+
+ ReadINIStr $2 "$INSTDIR\distribution\setup.ini" "OptionalExtensions" \
+ "extension.$0.checked"
+ ${If} $2 != ${BST_UNCHECKED}
+ ${LogMsg} "Installing optional extension: $1"
+ CopyFiles /SILENT "$INSTDIR\distribution\optional-extensions\$1.xpi" \
+ "$INSTDIR\distribution\extensions"
+ ${EndIf}
+
+ IntOp $0 $0 + 1
+ ${Loop}
+ ${EndIf}
+
+ ${LogMsg} "Removing the optional-extensions directory"
+ RMDir /r /REBOOTOK "$INSTDIR\distribution\optional-extensions"
+ ${EndIf}
+!endif
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+ ${If} $TmpVal == "HKLM"
+ ; Add the registry keys for allowed certificates.
+ ${AddMaintCertKeys}
+ ${EndIf}
+!endif
+
+!ifdef MOZ_DEFAULT_BROWSER_AGENT
+ ${If} $RegisterDefaultAgent != "0"
+ ExecWait '"$INSTDIR\default-browser-agent.exe" register-task $AppUserModelID' $0
+
+ ${If} $0 == 0x80070534 ; HRESULT_FROM_WIN32(ERROR_NONE_MAPPED)
+ ; The agent sometimes returns this error from trying to register the task
+ ; when we're running out of the MSI. The error is cryptic, but I believe
+ ; the cause is the fact that the MSI service runs us as SYSTEM, so
+ ; proxying the invocation through the shell gets the task registered as
+ ; the interactive user, which is what we want.
+ ; We use ExecInExplorer only as a fallback instead of always, because it
+ ; doesn't work in all environments; see bug 1602726.
+ ExecInExplorer::Exec "$INSTDIR\default-browser-agent.exe" \
+ /cmdargs "register-task $AppUserModelID"
+ ; We don't need Exec's return value, but don't leave it on the stack.
+ Pop $0
+ ${EndIf}
+
+ ${If} $RegisterDefaultAgent == ""
+ ; If the variable was unset, force it to a good value.
+ StrCpy $RegisterDefaultAgent 1
+ ${EndIf}
+ ${EndIf}
+ ; Remember whether we were told to skip registering the agent, so that updates
+ ; won't try to create a registration when they don't find an existing one.
+ WriteRegDWORD HKCU "Software\Mozilla\${AppName}\Installer\$AppUserModelID" \
+ "DidRegisterDefaultBrowserAgent" $RegisterDefaultAgent
+!endif
+SectionEnd
+
+; Cleanup operations to perform at the end of the installation.
+Section "-InstallEndCleanup"
+ SetDetailsPrint both
+ DetailPrint "$(STATUS_CLEANUP)"
+ SetDetailsPrint none
+
+ ; Maybe copy the post-signing data?
+ StrCpy $PostSigningData ""
+ ${GetParameters} $0
+ ClearErrors
+ ; We don't get post-signing data from the MSI.
+ ${GetOptions} $0 "/LaunchedFromMSI" $1
+ ${If} ${Errors}
+ ; The stub will handle copying the data if it ran us.
+ ClearErrors
+ ${GetOptions} $0 "/LaunchedFromStub" $1
+ ${If} ${Errors}
+ ; We're being run standalone, copy the data.
+ ${CopyPostSigningData}
+ Pop $PostSigningData
+ ${EndIf}
+ ${EndIf}
+
+ ${Unless} ${Silent}
+ ClearErrors
+ ${MUI_INSTALLOPTIONS_READ} $0 "summary.ini" "Field 4" "State"
+ ${If} "$0" == "1"
+ StrCpy $SetAsDefault true
+ ; For data migration in the app, we want to know what the default browser
+ ; value was before we changed it. To do so, we read it here and store it
+ ; in our own registry key.
+ StrCpy $0 ""
+ AppAssocReg::QueryCurrentDefault "http" "protocol" "effective"
+ Pop $1
+ ; If the method hasn't failed, $1 will contain the progid. Check:
+ ${If} "$1" != "method failed"
+ ${AndIf} "$1" != "method not available"
+ ; Read the actual command from the progid
+ ReadRegStr $0 HKCR "$1\shell\open\command" ""
+ ${EndIf}
+ ; If using the App Association Registry didn't happen or failed, fall back
+ ; to the effective http default:
+ ${If} "$0" == ""
+ ReadRegStr $0 HKCR "http\shell\open\command" ""
+ ${EndIf}
+ ; If we have something other than empty string now, write the value.
+ ${If} "$0" != ""
+ ClearErrors
+ WriteRegStr HKCU "Software\Mozilla\Firefox" "OldDefaultBrowserCommand" "$0"
+ ${EndIf}
+
+ ${LogHeader} "Setting as the default browser"
+ ; AddTaskbarSC is needed by MigrateTaskBarShortcut, which is called by
+ ; SetAsDefaultAppUserHKCU. If this is called via ExecCodeSegment,
+ ; MigrateTaskBarShortcut will not see the value of AddTaskbarSC, so we
+ ; send it via a register instead.
+ StrCpy $R0 $AddTaskbarSC
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $0
+ ${If} ${Errors}
+ Call SetAsDefaultAppUserHKCU
+ ${Else}
+ GetFunctionAddress $0 SetAsDefaultAppUserHKCU
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+ ${ElseIfNot} ${Errors}
+ StrCpy $SetAsDefault false
+ ${LogHeader} "Writing default-browser opt-out"
+ ClearErrors
+ WriteRegStr HKCU "Software\Mozilla\Firefox" "DefaultBrowserOptOut" "True"
+ ${If} ${Errors}
+ ${LogMsg} "Error writing default-browser opt-out"
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+
+ ; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
+ ${MigrateTaskBarShortcut} "$AddTaskbarSC"
+
+ ; Add the Firewall entries during install
+ Call AddFirewallEntries
+
+ ; Refresh desktop icons
+ ${RefreshShellIcons}
+
+ ${InstallEndCleanupCommon}
+
+ ${If} $PreventRebootRequired == "true"
+ SetRebootFlag false
+ ${EndIf}
+
+ ${If} ${RebootFlag}
+ ; Admin is required to delete files on reboot so only add the moz-delete if
+ ; the user is an admin. After calling UAC::IsAdmin $0 will equal 1 if the
+ ; user is an admin.
+ UAC::IsAdmin
+ ${If} "$0" == "1"
+ ; When a reboot is required give RefreshShellIcons time to finish the
+ ; refreshing the icons so the OS doesn't display the icons from helper.exe
+ Sleep 10000
+ ${LogHeader} "Reboot Required To Finish Installation"
+ ; ${FileMainEXE}.moz-upgrade should never exist but just in case...
+ ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-upgrade"
+ Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-upgrade"
+ ${EndUnless}
+
+ ${If} ${FileExists} "$INSTDIR\${FileMainEXE}"
+ ClearErrors
+ Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-delete"
+ ${Unless} ${Errors}
+ Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete"
+ ${EndUnless}
+ ${EndIf}
+
+ ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}"
+ CopyFiles /SILENT "$INSTDIR\uninstall\helper.exe" "$INSTDIR"
+ FileOpen $0 "$INSTDIR\${FileMainEXE}" w
+ FileWrite $0 "Will be deleted on restart"
+ Rename /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-upgrade" "$INSTDIR\${FileMainEXE}"
+ FileClose $0
+ Delete "$INSTDIR\${FileMainEXE}"
+ Rename "$INSTDIR\helper.exe" "$INSTDIR\${FileMainEXE}"
+ ${EndUnless}
+ ${EndIf}
+ ${EndIf}
+
+ Call WriteInstallationTelemetryData
+
+ StrCpy $InstallResult "success"
+
+ ; When we're using the GUI, .onGUIEnd sends the ping, but of course that isn't
+ ; invoked when we're running silently.
+ ${If} ${Silent}
+ Call SendPing
+ ${EndIf}
+SectionEnd
+
+################################################################################
+# Install Abort Survey Functions
+
+Function CustomAbort
+ ${If} "${AB_CD}" == "en-US"
+ ${AndIf} "$PageName" != ""
+ ${AndIf} ${FileExists} "$EXEDIR\core\distribution\distribution.ini"
+ ReadINIStr $0 "$EXEDIR\core\distribution\distribution.ini" "Global" "about"
+ ClearErrors
+ ${WordFind} "$0" "Funnelcake" "E#" $1
+ ${Unless} ${Errors}
+ ; Yes = fill out the survey and exit, No = don't fill out survey and exit,
+ ; Cancel = don't exit.
+ MessageBox MB_YESNO|MB_ICONEXCLAMATION \
+ "Would you like to tell us why you are canceling this installation?" \
+ IDYes +1 IDNO CustomAbort_finish
+ ${If} "$PageName" == "Welcome"
+ GetFunctionAddress $0 AbortSurveyWelcome
+ ${ElseIf} "$PageName" == "Options"
+ GetFunctionAddress $0 AbortSurveyOptions
+ ${ElseIf} "$PageName" == "Directory"
+ GetFunctionAddress $0 AbortSurveyDirectory
+ ${ElseIf} "$PageName" == "Shortcuts"
+ GetFunctionAddress $0 AbortSurveyShortcuts
+ ${ElseIf} "$PageName" == "Summary"
+ GetFunctionAddress $0 AbortSurveySummary
+ ${EndIf}
+ ClearErrors
+ ${GetParameters} $1
+ ${GetOptions} "$1" "/UAC:" $2
+ ${If} ${Errors}
+ Call $0
+ ${Else}
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+
+ CustomAbort_finish:
+ Return
+ ${EndUnless}
+ ${EndIf}
+
+ MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(MOZ_MUI_TEXT_ABORTWARNING)" \
+ IDYES +1 IDNO +2
+ Return
+ Abort
+FunctionEnd
+
+Function AbortSurveyWelcome
+ ExecShell "open" "${AbortSurveyURL}step1"
+FunctionEnd
+
+Function AbortSurveyOptions
+ ExecShell "open" "${AbortSurveyURL}step2"
+FunctionEnd
+
+Function AbortSurveyDirectory
+ ExecShell "open" "${AbortSurveyURL}step3"
+FunctionEnd
+
+Function AbortSurveyShortcuts
+ ExecShell "open" "${AbortSurveyURL}step4"
+FunctionEnd
+
+Function AbortSurveySummary
+ ExecShell "open" "${AbortSurveyURL}step5"
+FunctionEnd
+
+################################################################################
+# Helper Functions
+
+Function AddQuickLaunchShortcut
+ CreateShortCut "$QUICKLAUNCH\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$QUICKLAUNCH\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$QUICKLAUNCH\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${EndIf}
+FunctionEnd
+
+Function CheckExistingInstall
+ ; If there is a pending file copy from a previous upgrade don't allow
+ ; installing until after the system has rebooted.
+ IfFileExists "$INSTDIR\${FileMainEXE}.moz-upgrade" +1 +4
+ MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2
+ Reboot
+ Quit
+
+ ; If there is a pending file deletion from a previous uninstall don't allow
+ ; installing until after the system has rebooted.
+ IfFileExists "$INSTDIR\${FileMainEXE}.moz-delete" +1 +4
+ MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UNINSTALL)" IDNO +2
+ Reboot
+ Quit
+
+ ${If} ${FileExists} "$INSTDIR\${FileMainEXE}"
+ ; Disable the next, cancel, and back buttons
+ GetDlgItem $0 $HWNDPARENT 1 ; Next button
+ EnableWindow $0 0
+ GetDlgItem $0 $HWNDPARENT 2 ; Cancel button
+ EnableWindow $0 0
+ GetDlgItem $0 $HWNDPARENT 3 ; Back button
+ EnableWindow $0 0
+
+ Banner::show /NOUNLOAD "$(BANNER_CHECK_EXISTING)"
+
+ ${If} "$TmpVal" == "FoundAppWindow"
+ Sleep 5000
+ ${EndIf}
+
+ ${PushFilesToCheck}
+
+ ; Store the return value in $TmpVal so it is less likely to be accidentally
+ ; overwritten elsewhere.
+ ${CheckForFilesInUse} $TmpVal
+
+ Banner::destroy
+
+ ; Enable the next, cancel, and back buttons
+ GetDlgItem $0 $HWNDPARENT 1 ; Next button
+ EnableWindow $0 1
+ GetDlgItem $0 $HWNDPARENT 2 ; Cancel button
+ EnableWindow $0 1
+ GetDlgItem $0 $HWNDPARENT 3 ; Back button
+ EnableWindow $0 1
+
+ ; If there are files in use $TmpVal will be "true"
+ ${If} "$TmpVal" == "true"
+ ; If it finds a window of the right class, then ManualCloseAppPrompt will
+ ; abort leaving the value of $TmpVal set to "FoundAppWindow".
+ StrCpy $TmpVal "FoundAppWindow"
+ ${ManualCloseAppPrompt} "${MainWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_INSTALL)"
+ ${ManualCloseAppPrompt} "${DialogWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_INSTALL)"
+ StrCpy $TmpVal "true"
+ ${EndIf}
+ ${EndIf}
+FunctionEnd
+
+Function LaunchApp
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $1
+ ${If} ${Errors}
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -first-startup"
+ ${Else}
+ GetFunctionAddress $0 LaunchAppFromElevatedProcess
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+
+ StrCpy $LaunchedNewApp true
+FunctionEnd
+
+Function LaunchAppFromElevatedProcess
+ ; Set our current working directory to the application's install directory
+ ; otherwise the 7-Zip temp directory will be in use and won't be deleted.
+ SetOutPath "$INSTDIR"
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -first-startup"
+FunctionEnd
+
+Function SendPing
+ ${GetParameters} $0
+ ${GetOptions} $0 "/LaunchedFromStub" $0
+ ${IfNot} ${Errors}
+ Return
+ ${EndIf}
+
+ ; Create a GUID to use as the unique document ID.
+ System::Call "rpcrt4::UuidCreate(g . r0)i"
+ ; StringFromGUID2 (which is what System::Call uses internally to stringify
+ ; GUIDs) includes braces in its output, and we don't want those.
+ StrCpy $0 $0 -1 1
+
+ ; Configure the HTTP request for the ping
+ nsJSON::Set /tree ping /value "{}"
+ nsJSON::Set /tree ping "Url" /value \
+ '"${TELEMETRY_BASE_URL}/${TELEMETRY_NAMESPACE}/${TELEMETRY_INSTALL_PING_DOCTYPE}/${TELEMETRY_INSTALL_PING_VERSION}/$0"'
+ nsJSON::Set /tree ping "Verb" /value '"POST"'
+ nsJSON::Set /tree ping "DataType" /value '"JSON"'
+ nsJSON::Set /tree ping "AccessType" /value '"PreConfig"'
+
+ ; Fill in the ping payload
+ nsJSON::Set /tree ping "Data" /value "{}"
+ nsJSON::Set /tree ping "Data" "installer_type" /value '"full"'
+ nsJSON::Set /tree ping "Data" "installer_version" /value '"${AppVersion}"'
+ nsJSON::Set /tree ping "Data" "build_channel" /value '"${Channel}"'
+ nsJSON::Set /tree ping "Data" "update_channel" /value '"${UpdateChannel}"'
+ nsJSON::Set /tree ping "Data" "locale" /value '"${AB_CD}"'
+
+ ReadINIStr $0 "$INSTDIR\application.ini" "App" "Version"
+ nsJSON::Set /tree ping "Data" "version" /value '"$0"'
+ ReadINIStr $0 "$INSTDIR\application.ini" "App" "BuildID"
+ nsJSON::Set /tree ping "Data" "build_id" /value '"$0"'
+
+ ${GetParameters} $0
+ ${GetOptions} $0 "/LaunchedFromMSI" $0
+ ${IfNot} ${Errors}
+ nsJSON::Set /tree ping "Data" "from_msi" /value true
+ ${EndIf}
+
+ !ifdef HAVE_64BIT_BUILD
+ nsJSON::Set /tree ping "Data" "64bit_build" /value true
+ !else
+ nsJSON::Set /tree ping "Data" "64bit_build" /value false
+ !endif
+
+ ${If} ${RunningX64}
+ nsJSON::Set /tree ping "Data" "64bit_os" /value true
+ ${Else}
+ nsJSON::Set /tree ping "Data" "64bit_os" /value false
+ ${EndIf}
+
+ ; Though these values are sometimes incorrect due to bug 444664 it happens
+ ; so rarely it isn't worth working around it by reading the registry values.
+ ${WinVerGetMajor} $0
+ ${WinVerGetMinor} $1
+ ${WinVerGetBuild} $2
+ nsJSON::Set /tree ping "Data" "os_version" /value '"$0.$1.$2"'
+ ${If} ${IsServerOS}
+ nsJSON::Set /tree ping "Data" "server_os" /value true
+ ${Else}
+ nsJSON::Set /tree ping "Data" "server_os" /value false
+ ${EndIf}
+
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" \
+ "Write Test"
+ ${If} ${Errors}
+ nsJSON::Set /tree ping "Data" "admin_user" /value false
+ ${Else}
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ nsJSON::Set /tree ping "Data" "admin_user" /value true
+ ${EndIf}
+
+ ${If} $DefaultInstDir == $INSTDIR
+ nsJSON::Set /tree ping "Data" "default_path" /value true
+ ${Else}
+ nsJSON::Set /tree ping "Data" "default_path" /value false
+ ${EndIf}
+
+ nsJSON::Set /tree ping "Data" "set_default" /value "$SetAsDefault"
+
+ nsJSON::Set /tree ping "Data" "new_default" /value false
+ nsJSON::Set /tree ping "Data" "old_default" /value false
+
+ AppAssocReg::QueryCurrentDefault "http" "protocol" "effective"
+ Pop $0
+ ReadRegStr $0 HKCR "$0\shell\open\command" ""
+ ${If} $0 != ""
+ ${GetPathFromString} "$0" $0
+ ${GetParent} "$0" $1
+ ${GetLongPath} "$1" $1
+ ${If} $1 == $INSTDIR
+ nsJSON::Set /tree ping "Data" "new_default" /value true
+ ${Else}
+ StrCpy $0 "$0" "" -11 # 11 == length of "firefox.exe"
+ ${If} "$0" == "${FileMainEXE}"
+ nsJSON::Set /tree ping "Data" "old_default" /value true
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+ nsJSON::Set /tree ping "Data" "had_old_install" /value "$HadOldInstall"
+
+ ${If} ${Silent}
+ ; In silent mode, only the install phase is executed, and the GUI events
+ ; that initialize most of the phase times are never called; only
+ ; $InstallPhaseStart and $FinishPhaseStart have usable values.
+ ${GetSecondsElapsed} $InstallPhaseStart $FinishPhaseStart $0
+
+ nsJSON::Set /tree ping "Data" "intro_time" /value 0
+ nsJSON::Set /tree ping "Data" "options_time" /value 0
+ nsJSON::Set /tree ping "Data" "install_time" /value "$0"
+ nsJSON::Set /tree ping "Data" "finish_time" /value 0
+ ${Else}
+ ; In GUI mode, all we can be certain of is that the intro phase has started;
+ ; the user could have canceled at any time and phases after that won't
+ ; have run at all. So we have to be prepared for anything after
+ ; $IntroPhaseStart to be uninitialized. For anything that isn't filled in
+ ; yet we'll use the current tick count. That means that any phases that
+ ; weren't entered at all will get 0 for their times because the start and
+ ; end tick counts will be the same.
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $0
+
+ ${If} $OptionsPhaseStart == 0
+ StrCpy $OptionsPhaseStart $0
+ ${EndIf}
+ ${GetSecondsElapsed} $IntroPhaseStart $OptionsPhaseStart $1
+ nsJSON::Set /tree ping "Data" "intro_time" /value "$1"
+
+ ${If} $InstallPhaseStart == 0
+ StrCpy $InstallPhaseStart $0
+ ${EndIf}
+ ${GetSecondsElapsed} $OptionsPhaseStart $InstallPhaseStart $1
+ nsJSON::Set /tree ping "Data" "options_time" /value "$1"
+
+ ${If} $FinishPhaseStart == 0
+ StrCpy $FinishPhaseStart $0
+ ${EndIf}
+ ${GetSecondsElapsed} $InstallPhaseStart $FinishPhaseStart $1
+ nsJSON::Set /tree ping "Data" "install_time" /value "$1"
+
+ ${If} $FinishPhaseEnd == 0
+ StrCpy $FinishPhaseEnd $0
+ ${EndIf}
+ ${GetSecondsElapsed} $FinishPhaseStart $FinishPhaseEnd $1
+ nsJSON::Set /tree ping "Data" "finish_time" /value "$1"
+ ${EndIf}
+
+ ; $PostSigningData should only be empty if we didn't try to copy the
+ ; postSigningData file at all. If we did try and the file was missing
+ ; or empty, this will be "0", and for consistency with the stub we will
+ ; still submit it.
+ ${If} $PostSigningData != ""
+ nsJSON::Quote /always $PostSigningData
+ Pop $0
+ nsJSON::Set /tree ping "Data" "attribution" /value $0
+ ${EndIf}
+
+ nsJSON::Set /tree ping "Data" "new_launched" /value "$LaunchedNewApp"
+
+ nsJSON::Set /tree ping "Data" "succeeded" /value false
+ ${If} $InstallResult == "cancel"
+ nsJSON::Set /tree ping "Data" "user_cancelled" /value true
+ ${ElseIf} $InstallResult == "success"
+ nsJSON::Set /tree ping "Data" "succeeded" /value true
+ ${EndIf}
+
+ ${If} ${Silent}
+ nsJSON::Set /tree ping "Data" "silent" /value true
+ ${Else}
+ nsJSON::Set /tree ping "Data" "silent" /value false
+ ${EndIf}
+
+ ; Send the ping request. This call will block until a response is received,
+ ; but we shouldn't have any windows still open, so we won't jank anything.
+ nsJSON::Set /http ping
+FunctionEnd
+
+; Record data about this installation for use in in-app Telemetry pings.
+;
+; This should be run only after a successful installation, as it will
+; pull data from $INSTDIR\application.ini.
+;
+; Unlike the install ping or post-signing data, which is only sent/written by
+; the full installer when it is not run by the stub (since the stub has more
+; information), this will always be recorded by the full installer, to reduce
+; duplication and ensure consistency.
+;
+; Note: Should be assumed to clobber all $0, $1, etc registers.
+!define JSONSet `nsJSON::Set /tree installation_data`
+Function WriteInstallationTelemetryData
+ ${JSONSet} /value "{}"
+
+ ReadINIStr $0 "$INSTDIR\application.ini" "App" "Version"
+ ${JSONSet} "version" /value '"$0"'
+ ReadINIStr $0 "$INSTDIR\application.ini" "App" "BuildID"
+ ${JSONSet} "build_id" /value '"$0"'
+
+ ; Check for write access to HKLM, if successful then report this user
+ ; as an (elevated) admin.
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" \
+ "Write Test"
+ ${If} ${Errors}
+ StrCpy $1 "false"
+ ${Else}
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ StrCpy $1 "true"
+ ${EndIf}
+ ${JSONSet} "admin_user" /value $1
+
+ ; Note: This is not the same as $HadOldInstall, which looks for any install
+ ; in the registry. $InstallExisted is true only if this run of the installer
+ ; is replacing an existing main EXE.
+ ${If} $InstallExisted != ""
+ ${JSONSet} "install_existed" /value $InstallExisted
+ ${EndIf}
+
+ ; Check for top-level profile directory
+ ; Note: This is the same check used to set $ExistingProfile in stub.nsi
+ ${GetLocalAppDataFolder} $0
+ ${If} ${FileExists} "$0\Mozilla\Firefox"
+ StrCpy $1 "true"
+ ${Else}
+ StrCpy $1 "false"
+ ${EndIf}
+ ${JSONSet} "profdir_existed" /value $1
+
+ ${GetParameters} $0
+ ${GetOptions} $0 "/LaunchedFromStub" $1
+ ${IfNot} ${Errors}
+ ${JSONSet} "installer_type" /value '"stub"'
+ ${Else}
+ ; Not launched from stub
+ ${JSONSet} "installer_type" /value '"full"'
+
+ ; Include additional info relevant when the full installer is run directly
+
+ ${If} ${Silent}
+ StrCpy $1 "true"
+ ${Else}
+ StrCpy $1 "false"
+ ${EndIf}
+ ${JSONSet} "silent" /value $1
+
+ ${GetOptions} $0 "/LaunchedFromMSI" $1
+ ${IfNot} ${Errors}
+ StrCpy $1 "true"
+ ${Else}
+ StrCpy $1 "false"
+ ${EndIf}
+ ${JSONSet} "from_msi" /value $1
+
+ ; NOTE: for non-admin basic installs, or reinstalls, $DefaultInstDir may not
+ ; reflect the actual default path.
+ ${If} $DefaultInstDir == $INSTDIR
+ StrCpy $1 "true"
+ ${Else}
+ StrCpy $1 "false"
+ ${EndIf}
+ ${JSONSet} "default_path" /value $1
+ ${EndIf}
+
+ ; Timestamp, to allow app to detect a new install.
+ ; As a 64-bit integer isn't valid JSON, quote as a string.
+ System::Call "kernel32::GetSystemTimeAsFileTime(*l.r0)"
+ ${JSONSet} "install_timestamp" /value '"$0"'
+
+ nsJSON::Serialize /tree installation_data /file /unicode "$INSTDIR\installation_telemetry.json"
+FunctionEnd
+!undef JSONSet
+
+; Set $InstallExisted (if not yet set) by checking for the EXE.
+; Should be called before trying to delete the EXE when install begins.
+Function CheckIfInstallExisted
+ ${If} $InstallExisted == ""
+ ${If} ${FileExists} "$INSTDIR\${FileMainEXE}"
+ StrCpy $InstallExisted true
+ ${Else}
+ StrCpy $InstallExisted false
+ ${EndIf}
+ ${EndIf}
+FunctionEnd
+
+################################################################################
+# Language
+
+!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
+!verbose push
+!verbose 3
+!include "overrideLocale.nsh"
+!include "customLocale.nsh"
+!ifdef MOZ_OPTIONAL_EXTENSIONS
+!include "extensionsLocale.nsh"
+!endif
+!verbose pop
+
+; Set this after the locale files to override it if it is in the locale
+; using " " for BrandingText will hide the "Nullsoft Install System..." branding
+BrandingText " "
+
+################################################################################
+# Page pre, show, and leave functions
+
+Function preWelcome
+ StrCpy $PageName "Welcome"
+ ${If} ${FileExists} "$EXEDIR\core\distribution\modern-wizard.bmp"
+ Delete "$PLUGINSDIR\modern-wizard.bmp"
+ CopyFiles /SILENT "$EXEDIR\core\distribution\modern-wizard.bmp" "$PLUGINSDIR\modern-wizard.bmp"
+ ${EndIf}
+
+ ; We don't want the header bitmap showing on the welcome page.
+ GetDlgItem $0 $HWNDPARENT 1046
+ ShowWindow $0 ${SW_HIDE}
+
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $IntroPhaseStart
+FunctionEnd
+
+Function showWelcome
+ ; The welcome and finish pages don't get the correct colors for their labels
+ ; like the other pages do, presumably because they're built by filling in an
+ ; InstallOptions .ini file instead of from a dialog resource like the others.
+ ; Field 2 is the header and Field 3 is the body text.
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 2" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 3" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ; We need to overwrite the sidebar image so that we get it drawn with proper
+ ; scaling if the display is scaled at anything above 100%.
+ ${ChangeMUISidebarImage} "$PLUGINSDIR\modern-wizard.bmp"
+FunctionEnd
+
+Function leaveWelcome
+ ; Bring back the header bitmap for the next pages.
+ GetDlgItem $0 $HWNDPARENT 1046
+ ShowWindow $0 ${SW_SHOW}
+FunctionEnd
+
+Function preOptions
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $OptionsPhaseStart
+
+ ; The header and subheader on the wizard pages don't get the correct text
+ ; color by default for some reason, even though the other controls do.
+ GetDlgItem $0 $HWNDPARENT 1037
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+ GetDlgItem $0 $HWNDPARENT 1038
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ StrCpy $PageName "Options"
+ ${If} ${FileExists} "$EXEDIR\core\distribution\modern-header.bmp"
+ Delete "$PLUGINSDIR\modern-header.bmp"
+ CopyFiles /SILENT "$EXEDIR\core\distribution\modern-header.bmp" "$PLUGINSDIR\modern-header.bmp"
+ ${EndIf}
+ ${ChangeMUIHeaderImage} "$PLUGINSDIR\modern-header.bmp"
+ !insertmacro MUI_HEADER_TEXT "$(OPTIONS_PAGE_TITLE)" "$(OPTIONS_PAGE_SUBTITLE)"
+ !insertmacro MUI_INSTALLOPTIONS_DISPLAY "options.ini"
+FunctionEnd
+
+Function leaveOptions
+ ${MUI_INSTALLOPTIONS_READ} $0 "options.ini" "Settings" "State"
+ ${If} $0 != 0
+ Abort
+ ${EndIf}
+ ${MUI_INSTALLOPTIONS_READ} $R0 "options.ini" "Field 2" "State"
+ StrCmp $R0 "1" +1 +2
+ StrCpy $InstallType ${INSTALLTYPE_BASIC}
+ ${MUI_INSTALLOPTIONS_READ} $R0 "options.ini" "Field 3" "State"
+ StrCmp $R0 "1" +1 +2
+ StrCpy $InstallType ${INSTALLTYPE_CUSTOM}
+
+ ${LeaveOptionsCommon}
+
+ ${If} $InstallType == ${INSTALLTYPE_BASIC}
+ Call CheckExistingInstall
+ ${EndIf}
+FunctionEnd
+
+Function preDirectory
+ StrCpy $PageName "Directory"
+ ${PreDirectoryCommon}
+
+ StrCpy $DefaultInstDir $INSTDIR
+FunctionEnd
+
+Function leaveDirectory
+ ${If} $InstallType == ${INSTALLTYPE_BASIC}
+ Call CheckExistingInstall
+ ${EndIf}
+ ${LeaveDirectoryCommon} "$(WARN_DISK_SPACE)" "$(WARN_WRITE_ACCESS)"
+FunctionEnd
+
+Function preShortcuts
+ StrCpy $PageName "Shortcuts"
+ ${CheckCustomCommon}
+ !insertmacro MUI_HEADER_TEXT "$(SHORTCUTS_PAGE_TITLE)" "$(SHORTCUTS_PAGE_SUBTITLE)"
+ !insertmacro MUI_INSTALLOPTIONS_DISPLAY "shortcuts.ini"
+FunctionEnd
+
+Function leaveShortcuts
+ ${MUI_INSTALLOPTIONS_READ} $0 "shortcuts.ini" "Settings" "State"
+ ${If} $0 != 0
+ Abort
+ ${EndIf}
+ ${MUI_INSTALLOPTIONS_READ} $AddDesktopSC "shortcuts.ini" "Field 2" "State"
+ ${MUI_INSTALLOPTIONS_READ} $AddStartMenuSC "shortcuts.ini" "Field 3" "State"
+ ${MUI_INSTALLOPTIONS_READ} $AddTaskbarSC "shortcuts.ini" "Field 4" "State"
+
+ ${If} $InstallType == ${INSTALLTYPE_CUSTOM}
+ Call CheckExistingInstall
+ ${EndIf}
+FunctionEnd
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+Function preComponents
+ ; If the service already exists, don't show this page
+ ServicesHelper::IsInstalled "MozillaMaintenance"
+ Pop $R9
+ ${If} $R9 == 1
+ ; The service already exists so don't show this page.
+ Abort
+ ${EndIf}
+
+ ; Don't show the custom components page if the
+ ; user is not an admin
+ Call IsUserAdmin
+ Pop $R9
+ ${If} $R9 != "true"
+ Abort
+ ${EndIf}
+
+ ; Only show the maintenance service page if we have write access to HKLM
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" \
+ "${BrandShortName}InstallerTest" "Write Test"
+ ${If} ${Errors}
+ ClearErrors
+ Abort
+ ${Else}
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ ${EndIf}
+
+ StrCpy $PageName "Components"
+ ${CheckCustomCommon}
+ !insertmacro MUI_HEADER_TEXT "$(COMPONENTS_PAGE_TITLE)" "$(COMPONENTS_PAGE_SUBTITLE)"
+ !insertmacro MUI_INSTALLOPTIONS_DISPLAY "components.ini"
+FunctionEnd
+
+Function leaveComponents
+ ${MUI_INSTALLOPTIONS_READ} $0 "components.ini" "Settings" "State"
+ ${If} $0 != 0
+ Abort
+ ${EndIf}
+ ${MUI_INSTALLOPTIONS_READ} $InstallMaintenanceService "components.ini" "Field 2" "State"
+ ${If} $InstallType == ${INSTALLTYPE_CUSTOM}
+ Call CheckExistingInstall
+ ${EndIf}
+FunctionEnd
+!endif
+
+!ifdef MOZ_OPTIONAL_EXTENSIONS
+Function preExtensions
+ StrCpy $PageName "Extensions"
+ ${CheckCustomCommon}
+
+ ; Abort if no optional extensions configured in distribution/setup.ini
+ ${If} ${FileExists} "$EXEDIR\core\distribution\setup.ini"
+ ClearErrors
+ ReadINIStr $ExtensionRecommender "$EXEDIR\core\distribution\setup.ini" \
+ "OptionalExtensions" "Recommender.${AB_CD}"
+ ${If} ${Errors}
+ ClearErrors
+ ReadINIStr $ExtensionRecommender "$EXEDIR\core\distribution\setup.ini" \
+ "OptionalExtensions" "Recommender"
+ ${EndIf}
+
+ ${If} ${Errors}
+ ClearErrors
+ Abort
+ ${EndIf}
+ ${Else}
+ Abort
+ ${EndIf}
+
+ !insertmacro MUI_HEADER_TEXT "$(EXTENSIONS_PAGE_TITLE)" "$(EXTENSIONS_PAGE_SUBTITLE)"
+ !insertmacro MUI_INSTALLOPTIONS_DISPLAY "extensions.ini"
+FunctionEnd
+
+Function leaveExtensions
+ ${MUI_INSTALLOPTIONS_READ} $0 "extensions.ini" "Settings" "NumFields"
+ ${MUI_INSTALLOPTIONS_READ} $1 "extensions.ini" "Settings" "State"
+
+ ; $0 is count of checkboxes
+ IntOp $0 $0 - 1
+
+ ${If} $1 > $0
+ Abort
+ ${ElseIf} $1 == 0
+ ; $1 is count of selected optional extension(s)
+ StrCpy $1 0
+
+ StrCpy $2 2
+ ${Do}
+ ${MUI_INSTALLOPTIONS_READ} $3 "extensions.ini" "Field $2" "State"
+ ${If} $3 == ${BST_CHECKED}
+ IntOp $1 $1 + 1
+ ${EndIf}
+
+ IntOp $4 $2 - 2
+ WriteINIStr "$EXEDIR\core\distribution\setup.ini" \
+ "OptionalExtensions" "extension.$4.checked" "$3"
+
+ ${If} $0 == $2
+ ${ExitDo}
+ ${Else}
+ IntOp $2 $2 + 1
+ ${EndIf}
+ ${Loop}
+
+ ; Different from state of field 1, "0" means no optional extensions selected
+ ${If} $1 > 0
+ StrCpy $InstallOptionalExtensions "1"
+ ${Else}
+ StrCpy $InstallOptionalExtensions "0"
+ ${EndIf}
+
+ ${If} $InstallType == ${INSTALLTYPE_CUSTOM}
+ Call CheckExistingInstall
+ ${EndIf}
+ ${ElseIf} $1 == 1
+ ; Check/uncheck all optional extensions with field 1
+ ${MUI_INSTALLOPTIONS_READ} $1 "extensions.ini" "Field 1" "State"
+
+ StrCpy $2 2
+ ${Do}
+ ${MUI_INSTALLOPTIONS_READ} $3 "extensions.ini" "Field $2" "HWND"
+ SendMessage $3 ${BM_SETCHECK} $1 0
+
+ ${If} $0 == $2
+ ${ExitDo}
+ ${Else}
+ IntOp $2 $2 + 1
+ ${EndIf}
+ ${Loop}
+
+ Abort
+ ${ElseIf} $1 > 1
+ StrCpy $1 ${BST_CHECKED}
+
+ StrCpy $2 2
+ ${Do}
+ ${MUI_INSTALLOPTIONS_READ} $3 "extensions.ini" "Field $2" "State"
+ ${If} $3 == ${BST_UNCHECKED}
+ StrCpy $1 ${BST_UNCHECKED}
+ ${ExitDo}
+ ${EndIf}
+
+ ${If} $0 == $2
+ ${ExitDo}
+ ${Else}
+ IntOp $2 $2 + 1
+ ${EndIf}
+ ${Loop}
+
+ ; Check field 1 only if all optional extensions are selected
+ ${MUI_INSTALLOPTIONS_READ} $3 "extensions.ini" "Field 1" "HWND"
+ SendMessage $3 ${BM_SETCHECK} $1 0
+
+ Abort
+ ${EndIf}
+FunctionEnd
+!endif
+
+Function preSummary
+ StrCpy $PageName "Summary"
+ ; Setup the summary.ini file for the Custom Summary Page
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "3"
+
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Type "label"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Text "$(SUMMARY_INSTALLED_TO)"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Left "0"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Right "-1"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Top "5"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Bottom "15"
+
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Type "text"
+ ; The contents of this control must be set as follows in the pre function
+ ; ${MUI_INSTALLOPTIONS_READ} $1 "summary.ini" "Field 2" "HWND"
+ ; SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" state ""
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Left "0"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Right "-1"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Top "17"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Bottom "30"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" flags "READONLY"
+
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Type "label"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Left "0"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Right "-1"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Top "130"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Bottom "150"
+
+ ${If} ${FileExists} "$INSTDIR\${FileMainEXE}"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Text "$(SUMMARY_UPGRADE_CLICK)"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NextButtonText "$(UPGRADE_BUTTON)"
+ ${Else}
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Text "$(SUMMARY_INSTALL_CLICK)"
+ DeleteINIStr "$PLUGINSDIR\summary.ini" "Settings" NextButtonText
+ ${EndIf}
+
+
+ ; Remove the "Field 4" ini section in case the user hits back and changes the
+ ; installation directory which could change whether the make default checkbox
+ ; should be displayed.
+ DeleteINISec "$PLUGINSDIR\summary.ini" "Field 4"
+
+ ; Check if it is possible to write to HKLM
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
+ ${Unless} ${Errors}
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ ; Check if Firefox is the http handler for this user.
+ SetShellVarContext current ; Set SHCTX to the current user
+ ${IsHandlerForInstallDir} "http" $R9
+ ; If Firefox isn't the http handler for this user show the option to set
+ ; Firefox as the default browser.
+ ${If} "$R9" != "true"
+ ${AndIf} ${AtMostWin2008R2}
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "4"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Text "$(SUMMARY_TAKE_DEFAULTS)"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Left "0"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Right "-1"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" State "1"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Top "32"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Bottom "53"
+ ${EndIf}
+ ${EndUnless}
+
+ ${If} "$TmpVal" == "true"
+ ; If there is already a Type entry in the "Field 4" section with a value of
+ ; checkbox then the set as the default browser checkbox is displayed and
+ ; this text must be moved below it.
+ ReadINIStr $0 "$PLUGINSDIR\summary.ini" "Field 4" "Type"
+ ${If} "$0" == "checkbox"
+ StrCpy $0 "5"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Top "53"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Bottom "68"
+ ${Else}
+ StrCpy $0 "4"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Top "35"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Bottom "50"
+ ${EndIf}
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "$0"
+
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Type "label"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Text "$(SUMMARY_REBOOT_REQUIRED_INSTALL)"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Left "0"
+ WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Right "-1"
+ ${EndIf}
+
+ !insertmacro MUI_HEADER_TEXT "$(SUMMARY_PAGE_TITLE)" "$(SUMMARY_PAGE_SUBTITLE)"
+
+ ; The Summary custom page has a textbox that will automatically receive
+ ; focus. This sets the focus to the Install button instead.
+ !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "summary.ini"
+ GetDlgItem $0 $HWNDPARENT 1
+ System::Call "user32::SetFocus(i r0, i 0x0007, i,i)i"
+ ${MUI_INSTALLOPTIONS_READ} $1 "summary.ini" "Field 2" "HWND"
+ SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR"
+ !insertmacro MUI_INSTALLOPTIONS_SHOW
+FunctionEnd
+
+Function leaveSummary
+ Call CheckIfInstallExisted
+
+ ; Try to delete the app executable and if we can't delete it try to find the
+ ; app's message window and prompt the user to close the app. This allows
+ ; running an instance that is located in another directory. If for whatever
+ ; reason there is no message window we will just rename the app's files and
+ ; then remove them on restart.
+ ClearErrors
+ ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+ ${If} ${Errors}
+ ${ManualCloseAppPrompt} "${MainWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_INSTALL)"
+ ${ManualCloseAppPrompt} "${DialogWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_INSTALL)"
+ ${EndIf}
+FunctionEnd
+
+; When we add an optional action to the finish page the cancel button is
+; enabled. This disables it and leaves the finish button as the only choice.
+Function preFinish
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $FinishPhaseStart
+
+ StrCpy $PageName ""
+ ${EndInstallLog} "${BrandFullName}"
+ !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "cancelenabled" "0"
+
+ ; We don't want the header bitmap showing on the finish page.
+ GetDlgItem $0 $HWNDPARENT 1046
+ ShowWindow $0 ${SW_HIDE}
+FunctionEnd
+
+Function showFinish
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 2" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 3" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ; We need to overwrite the sidebar image so that we get it drawn with proper
+ ; scaling if the display is scaled at anything above 100%.
+ ${ChangeMUISidebarImage} "$PLUGINSDIR\modern-wizard.bmp"
+
+ ; Field 4 is the launch checkbox. Since it's a checkbox, we need to
+ ; clear the theme from it before we can set its background color.
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 4" "HWND"
+ System::Call 'uxtheme::SetWindowTheme(i $0, w " ", w " ")'
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+FunctionEnd
+
+Function postFinish
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $FinishPhaseEnd
+FunctionEnd
+
+################################################################################
+# Initialization Functions
+
+Function .onInit
+ ; Remove the current exe directory from the search order.
+ ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
+ System::Call 'kernel32::SetDllDirectoryW(w "")'
+
+ ; Initialize the variables used for telemetry
+ StrCpy $SetAsDefault true
+ StrCpy $HadOldInstall false
+ StrCpy $InstallExisted ""
+ StrCpy $DefaultInstDir $INSTDIR
+ StrCpy $IntroPhaseStart 0
+ StrCpy $OptionsPhaseStart 0
+ StrCpy $InstallPhaseStart 0
+ StrCpy $FinishPhaseStart 0
+ StrCpy $FinishPhaseEnd 0
+ StrCpy $InstallResult "cancel"
+ StrCpy $LaunchedNewApp false
+
+ StrCpy $PageName ""
+ StrCpy $LANGUAGE 0
+ ${SetBrandNameVars} "$EXEDIR\core\distribution\setup.ini"
+
+ ; 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. Result returned in $R7.
+ System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R7"
+
+ ; Windows NT 6.0 (Vista/Server 2008) and lower are not supported.
+ ${Unless} ${AtLeastWin7}
+ ${If} "$R7" == "0"
+ strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_CPU_MSG)"
+ ${Else}
+ strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_MSG)"
+ ${EndIf}
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$R7" IDCANCEL +2
+ ExecShell "open" "${URLSystemRequirements}"
+ Quit
+ ${EndUnless}
+
+ ; SSE2 CPU support
+ ${If} "$R7" == "0"
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_CPU_MSG)" IDCANCEL +2
+ ExecShell "open" "${URLSystemRequirements}"
+ Quit
+ ${EndIf}
+
+!ifdef HAVE_64BIT_BUILD
+ ${If} "${ARCH}" == "AArch64"
+ ${IfNot} ${IsNativeARM64}
+ ${OrIfNot} ${AtLeastWin10}
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_OSVER_MSG)" IDCANCEL +2
+ ExecShell "open" "${URLSystemRequirements}"
+ Quit
+ ${EndIf}
+ ${ElseIfNot} ${RunningX64}
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_OSVER_MSG)" IDCANCEL +2
+ ExecShell "open" "${URLSystemRequirements}"
+ Quit
+ ${EndIf}
+ SetRegView 64
+!endif
+
+ SetShellVarContext all
+ ${GetFirstInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $0
+ ${If} "$0" == "false"
+ SetShellVarContext current
+ ${GetFirstInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $0
+ ${If} "$0" == "false"
+ StrCpy $HadOldInstall false
+ ${Else}
+ StrCpy $HadOldInstall true
+ ${EndIf}
+ ${Else}
+ StrCpy $HadOldInstall true
+ ${EndIf}
+
+ ${InstallOnInitCommon} "$(WARN_MIN_SUPPORTED_OSVER_CPU_MSG)"
+
+ !insertmacro InitInstallOptionsFile "options.ini"
+ !insertmacro InitInstallOptionsFile "shortcuts.ini"
+ !insertmacro InitInstallOptionsFile "components.ini"
+ !insertmacro InitInstallOptionsFile "extensions.ini"
+ !insertmacro InitInstallOptionsFile "summary.ini"
+
+ WriteINIStr "$PLUGINSDIR\options.ini" "Settings" NumFields "5"
+
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Type "label"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Text "$(OPTIONS_SUMMARY)"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Left "0"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Right "-1"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Top "0"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Bottom "10"
+
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Type "RadioButton"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Text "$(OPTION_STANDARD_RADIO)"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left "0"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Right "-1"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Top "25"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Bottom "35"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" State "1"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Flags "GROUP"
+
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Type "RadioButton"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Text "$(OPTION_CUSTOM_RADIO)"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left "0"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Right "-1"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Top "55"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Bottom "65"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" State "0"
+
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Type "label"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Text "$(OPTION_STANDARD_DESC)"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left "15"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Right "-1"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Top "37"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Bottom "57"
+
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Type "label"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Text "$(OPTION_CUSTOM_DESC)"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left "15"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Right "-1"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Top "67"
+ WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Bottom "87"
+
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Settings" NumFields "4"
+
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Type "label"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Text "$(CREATE_ICONS_DESC)"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Left "0"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Right "-1"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Top "5"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Bottom "15"
+
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Text "$(ICONS_DESKTOP)"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left "0"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Right "-1"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Top "20"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Bottom "30"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" State "1"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Flags "GROUP"
+
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Text "$(ICONS_STARTMENU)"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left "0"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Right "-1"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Top "40"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Bottom "50"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" State "1"
+
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Text "$(ICONS_TASKBAR)"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left "0"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Right "-1"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Top "60"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Bottom "70"
+ WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" State "1"
+
+ ; Setup the components.ini file for the Components Page
+ WriteINIStr "$PLUGINSDIR\components.ini" "Settings" NumFields "2"
+
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Type "label"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Text "$(OPTIONAL_COMPONENTS_DESC)"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Left "0"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Right "-1"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Top "5"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Bottom "25"
+
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Text "$(MAINTENANCE_SERVICE_CHECKBOX_DESC)"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Left "0"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Right "-1"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Top "27"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Bottom "37"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" State "1"
+ WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Flags "GROUP"
+
+ ; Setup the extensions.ini file for the Custom Extensions Page
+ StrCpy $R9 0
+ StrCpy $R8 ${BST_CHECKED}
+
+ ${If} ${FileExists} "$EXEDIR\core\distribution\setup.ini"
+ ${Do}
+ IntOp $R7 $R9 + 2
+
+ ClearErrors
+ ReadINIStr $R6 "$EXEDIR\core\distribution\setup.ini" \
+ "OptionalExtensions" "extension.$R9.name.${AB_CD}"
+ ${If} ${Errors}
+ ClearErrors
+ ReadINIStr $R6 "$EXEDIR\core\distribution\setup.ini" \
+ "OptionalExtensions" "extension.$R9.name"
+ ${EndIf}
+
+ ${If} ${Errors}
+ ${ExitDo}
+ ${EndIf}
+
+ ; Each row moves down by 13 DLUs
+ IntOp $R2 $R9 * 13
+ IntOp $R2 $R2 + 21
+ IntOp $R1 $R2 + 10
+
+ ClearErrors
+ ReadINIStr $R0 "$EXEDIR\core\distribution\setup.ini" \
+ "OptionalExtensions" "extension.$R9.checked"
+ ${If} ${Errors}
+ StrCpy $R0 ${BST_CHECKED}
+ ${ElseIf} $R0 == "0"
+ StrCpy $R8 ${BST_UNCHECKED}
+ ${EndIf}
+
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Text "$R6"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Left "11"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Right "-1"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Top "$R2"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Bottom "$R1"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" State "$R0"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R7" Flags "NOTIFY"
+
+ IntOp $R9 $R9 + 1
+ ${Loop}
+ ${EndIf}
+
+ IntOp $R9 $R9 + 2
+
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Settings" NumFields "$R9"
+
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Type "checkbox"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Text "$(OPTIONAL_EXTENSIONS_CHECKBOX_DESC)"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Left "0"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Right "-1"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Top "5"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Bottom "15"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" State "$R8"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field 1" Flags "GROUP|NOTIFY"
+
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R9" Type "label"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R9" Text "$(OPTIONAL_EXTENSIONS_DESC)"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R9" Left "0"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R9" Right "-1"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R9" Top "-23"
+ WriteINIStr "$PLUGINSDIR\extensions.ini" "Field $R9" Bottom "-5"
+
+ ; There must always be a core directory.
+ ${GetSize} "$EXEDIR\core\" "/S=0K" $R5 $R7 $R8
+ SectionSetSize ${APP_IDX} $R5
+
+ ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if
+ ; the user clicks the back button
+ StrCpy $hHeaderBitmap ""
+FunctionEnd
+
+Function .onGUIEnd
+ ${OnEndCommon}
+ Call SendPing
+FunctionEnd
diff --git a/browser/installer/windows/nsis/maintenanceservice_installer.nsi b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
new file mode 100644
index 0000000000..ff87ef0839
--- /dev/null
+++ b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -0,0 +1,343 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
+!verbose 3
+
+; 7-Zip provides better compression than the lzma from NSIS so we add the files
+; uncompressed and use 7-Zip to create a SFX archive of it
+SetDatablockOptimize on
+SetCompress off
+CRCCheck on
+
+RequestExecutionLevel admin
+
+Unicode true
+ManifestSupportedOS all
+ManifestDPIAware true
+
+!addplugindir ./
+
+; Variables
+Var TempMaintServiceName
+Var BrandFullNameDA
+Var BrandFullName
+
+; Other included files may depend upon these includes!
+; The following includes are provided by NSIS.
+!include FileFunc.nsh
+!include LogicLib.nsh
+!include MUI.nsh
+!include WinMessages.nsh
+!include WinVer.nsh
+!include WordFunc.nsh
+
+!insertmacro GetOptions
+!insertmacro GetParameters
+!insertmacro GetSize
+
+; The test machines use this fallback key to run tests.
+; And anyone that wants to run tests themselves should already have
+; this installed.
+!define FallbackKey \
+ "SOFTWARE\Mozilla\MaintenanceService\3932ecacee736d366d6436db0f55bce4"
+
+!define CompanyName "Mozilla Corporation"
+!define BrandFullNameInternal ""
+
+; The following includes are custom.
+!include defines.nsi
+; We keep defines.nsi defined so that we get other things like
+; the version number, but we redefine BrandFullName
+!define MaintFullName "Mozilla Maintenance Service"
+!ifdef BrandFullName
+!undef BrandFullName
+!endif
+!define BrandFullName "${MaintFullName}"
+
+!include common.nsh
+!include locales.nsi
+
+VIAddVersionKey "FileDescription" "${MaintFullName} Installer"
+VIAddVersionKey "OriginalFilename" "maintenanceservice_installer.exe"
+
+Name "${MaintFullName}"
+OutFile "maintenanceservice_installer.exe"
+
+; Get installation folder from registry if available
+InstallDirRegKey HKLM "Software\Mozilla\MaintenanceService" ""
+
+SetOverwrite on
+
+; serviceinstall.cpp also uses this key, in case the path is changed, update
+; there too.
+!define MaintUninstallKey \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\MozillaMaintenanceService"
+
+; Always install into the 32-bit location even if we have a 64-bit build.
+; This is because we use only 1 service for all Firefox channels.
+; Allow either x86 and x64 builds to exist at this location, depending on
+; what is the latest build.
+InstallDir "$PROGRAMFILES32\${MaintFullName}\"
+ShowUnInstDetails nevershow
+
+################################################################################
+# Modern User Interface - MUI
+
+!define MUI_ICON setup.ico
+!define MUI_UNICON setup.ico
+!define MUI_WELCOMEPAGE_TITLE_3LINES
+!define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
+
+;Interface Settings
+!define MUI_ABORTWARNING
+
+; Uninstaller Pages
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+
+################################################################################
+# Language
+
+!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
+!verbose push
+!verbose 3
+!include "overrideLocale.nsh"
+!include "customLocale.nsh"
+!verbose pop
+
+; Set this after the locale files to override it if it is in the locale
+; using " " for BrandingText will hide the "Nullsoft Install System..." branding
+BrandingText " "
+
+Function .onInit
+ ; Remove the current exe directory from the search order.
+ ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
+ System::Call 'kernel32::SetDllDirectoryW(w "")'
+
+ SetSilent silent
+
+ ${Unless} ${AtLeastWin7}
+ Abort
+ ${EndUnless}
+FunctionEnd
+
+Function un.onInit
+ ; Remove the current exe directory from the search order.
+ ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
+ System::Call 'kernel32::SetDllDirectoryW(w "")'
+
+ StrCpy $BrandFullNameDA "${MaintFullName}"
+ StrCpy $BrandFullName "${MaintFullName}"
+FunctionEnd
+
+Section "MaintenanceService"
+ AllowSkipFiles off
+
+ CreateDirectory $INSTDIR
+ SetOutPath $INSTDIR
+
+ ; If the service already exists, then it will be stopped when upgrading it
+ ; via the maintenanceservice_tmp.exe command executed below.
+ ; The maintenanceservice_tmp.exe command will rename the file to
+ ; maintenanceservice.exe if maintenanceservice_tmp.exe is newer.
+ ; If the service does not exist yet, we install it and drop the file on
+ ; disk as maintenanceservice.exe directly.
+ StrCpy $TempMaintServiceName "maintenanceservice.exe"
+ IfFileExists "$INSTDIR\maintenanceservice.exe" 0 skipAlreadyExists
+ StrCpy $TempMaintServiceName "maintenanceservice_tmp.exe"
+ skipAlreadyExists:
+
+ ; We always write out a copy and then decide whether to install it or
+ ; not via calling its 'install' cmdline which works by version comparison.
+ CopyFiles /SILENT "$EXEDIR\maintenanceservice.exe" "$INSTDIR\$TempMaintServiceName"
+
+ ; The updater.ini file is only used when performing an install or upgrade,
+ ; and only if that install or upgrade is successful. If an old updater.ini
+ ; happened to be copied into the maintenance service installation directory
+ ; but the service was not newer, the updater.ini file would be unused.
+ ; It is used to fill the description of the service on success.
+ CopyFiles /SILENT "$EXEDIR\updater.ini" "$INSTDIR\updater.ini"
+
+ ; Install the application maintenance service.
+ ; If a service already exists, the command line parameter will stop the
+ ; service and only install itself if it is newer than the already installed
+ ; service. If successful it will remove the old maintenanceservice.exe
+ ; and replace it with maintenanceservice_tmp.exe.
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/Upgrade" $0
+ ${If} ${Errors}
+ ExecWait '"$INSTDIR\$TempMaintServiceName" install'
+ ${Else}
+ ; The upgrade cmdline is the same as install except
+ ; It will fail if the service isn't already installed.
+ ExecWait '"$INSTDIR\$TempMaintServiceName" upgrade'
+ ${EndIf}
+
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ ; Since the Maintenance service can be installed either x86 or x64,
+ ; always use the 64-bit registry.
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ ; Previous versions always created the uninstall key in the 32-bit registry.
+ ; Clean those old entries out if they still exist.
+ SetRegView 32
+ DeleteRegKey HKLM "${MaintUninstallKey}"
+ ; Preserve the lastused value before we switch to 64.
+ SetRegView lastused
+
+ SetRegView 64
+ ${EndIf}
+
+ WriteRegStr HKLM "${MaintUninstallKey}" "DisplayName" "${MaintFullName}"
+ WriteRegStr HKLM "${MaintUninstallKey}" "UninstallString" \
+ '"$INSTDIR\uninstall.exe"'
+ WriteRegStr HKLM "${MaintUninstallKey}" "DisplayIcon" \
+ "$INSTDIR\Uninstall.exe,0"
+ WriteRegStr HKLM "${MaintUninstallKey}" "DisplayVersion" "${AppVersion}"
+ WriteRegStr HKLM "${MaintUninstallKey}" "Publisher" "Mozilla"
+ WriteRegStr HKLM "${MaintUninstallKey}" "Comments" "${BrandFullName}"
+ WriteRegDWORD HKLM "${MaintUninstallKey}" "NoModify" 1
+ ${GetSize} "$INSTDIR" "/S=0K" $R2 $R3 $R4
+ WriteRegDWORD HKLM "${MaintUninstallKey}" "EstimatedSize" $R2
+
+ ; Write out that a maintenance service was attempted.
+ ; We do this because on upgrades we will check this value and we only
+ ; want to install once on the first upgrade to maintenance service.
+ ; Also write out that we are currently installed, preferences will check
+ ; this value to determine if we should show the service update pref.
+ WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
+ WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Installed" 1
+ DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled"
+
+ ; Included here for debug purposes only.
+ ; These keys are used to bypass the installation dir is a valid installation
+ ; check from the service so that tests can be run.
+ ; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation"
+ ; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "DigiCert SHA2 Assured ID Code Signing CA"
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView lastused
+ ${EndIf}
+SectionEnd
+
+; By renaming before deleting we improve things slightly in case
+; there is a file in use error. In this case a new install can happen.
+Function un.RenameDelete
+ Pop $9
+ ; If the .moz-delete file already exists previously, delete it
+ ; If it doesn't exist, the call is ignored.
+ ; We don't need to pass /REBOOTOK here since it was already marked that way
+ ; if it exists.
+ Delete "$9.moz-delete"
+ Rename "$9" "$9.moz-delete"
+ ${If} ${Errors}
+ Delete /REBOOTOK "$9"
+ ${Else}
+ Delete /REBOOTOK "$9.moz-delete"
+ ${EndIf}
+ ClearErrors
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; NOTE: The maintenance service uninstaller does not currently get updated when
+; the service itself does during application updates. Under normal use, only
+; running the Firefox installer will generate a new maintenance service
+; uninstaller. That means anything added here will not be seen by users until
+; they run a new Firefox installer. Fixing this is tracked in
+; https://bugzilla.mozilla.org/show_bug.cgi?id=1665193
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Section "Uninstall"
+ ; Delete the service so that no updates will be attempted
+ ExecWait '"$INSTDIR\maintenanceservice.exe" uninstall'
+
+ Push "$INSTDIR\updater.ini"
+ Call un.RenameDelete
+ Push "$INSTDIR\maintenanceservice.exe"
+ Call un.RenameDelete
+ Push "$INSTDIR\maintenanceservice_tmp.exe"
+ Call un.RenameDelete
+ Push "$INSTDIR\maintenanceservice.old"
+ Call un.RenameDelete
+ Push "$INSTDIR\Uninstall.exe"
+ Call un.RenameDelete
+ Push "$INSTDIR\update\updater.ini"
+ Call un.RenameDelete
+ Push "$INSTDIR\update\updater.exe"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-1.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-2.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-3.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-4.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-5.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-6.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-7.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-8.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-9.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-10.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-install.log"
+ Call un.RenameDelete
+ Push "$INSTDIR\logs\maintenanceservice-uninstall.log"
+ Call un.RenameDelete
+ SetShellVarContext all
+ Push "$APPDATA\Mozilla\logs\maintenanceservice.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-1.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-2.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-3.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-4.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-5.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-6.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-7.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-8.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-9.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-10.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-install.log"
+ Call un.RenameDelete
+ Push "$APPDATA\Mozilla\logs\maintenanceservice-uninstall.log"
+ Call un.RenameDelete
+ RMDir /REBOOTOK "$APPDATA\Mozilla\logs"
+ RMDir /REBOOTOK "$APPDATA\Mozilla"
+ RMDir /REBOOTOK "$INSTDIR\logs"
+ RMDir /REBOOTOK "$INSTDIR\update"
+ RMDir /REBOOTOK "$INSTDIR\UpdateLogs"
+ RMDir /REBOOTOK "$INSTDIR"
+
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView 64
+ ${EndIf}
+ DeleteRegKey HKLM "${MaintUninstallKey}"
+ DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed"
+ DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled"
+ DeleteRegKey HKLM "${FallbackKey}\"
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView lastused
+ ${EndIf}
+SectionEnd
diff --git a/browser/installer/windows/nsis/shared.nsh b/browser/installer/windows/nsis/shared.nsh
new file mode 100755
index 0000000000..dd85dfed8e
--- /dev/null
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -0,0 +1,1808 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+!macro PostUpdate
+ ${CreateShortcutsLog}
+
+ ; Remove registry entries for non-existent apps and for apps that point to our
+ ; install location in the Software\Mozilla key and uninstall registry entries
+ ; that point to our install location for both HKCU and HKLM.
+ SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
+ ${RegCleanMain} "Software\Mozilla"
+ ${RegCleanUninstall}
+ ${UpdateProtocolHandlers}
+
+ ; setup the application model id registration value
+ ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
+
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
+ ${If} ${Errors}
+ StrCpy $TmpVal "HKCU"
+ ${Else}
+ SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ StrCpy $TmpVal "HKLM"
+ ${RegCleanMain} "Software\Mozilla"
+ ${RegCleanUninstall}
+ ${UpdateProtocolHandlers}
+ ${FixShellIconHandler} "HKLM"
+ ${SetAppLSPCategories} ${LSP_CATEGORIES}
+
+ ; Add the Firewall entries after an update
+ Call AddFirewallEntries
+
+ ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
+ ${If} "$0" != "${GREVersion}"
+ WriteRegStr HKLM "Software\mozilla.org\Mozilla" "CurrentVersion" "${GREVersion}"
+ ${EndIf}
+ ${EndIf}
+
+ ; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
+ ; When we enabled this feature for Windows 10 & 11 we decided _not_ to pin
+ ; during an update (even once) because we already offered to do when the
+ ; the user originally installed, and we don't want to go against their
+ ; explicit wishes.
+ ; For Windows 7 and 8, we've been doing this ~forever, and those users may
+ ; not have experienced the onboarding offer to pin to taskbar, so we're
+ ; leaving it enabled there.
+ ${If} ${AtMostWin2012R2}
+ ${MigrateTaskBarShortcut} "$AddTaskbarSC"
+ ${EndIf}
+
+ ; Update the name/icon/AppModelID of our shortcuts as needed, then update the
+ ; lastwritetime of the Start Menu shortcut to clear the tile icon cache.
+ ; Do this for both shell contexts in case the user has shortcuts in multiple
+ ; locations, then restore the previous context at the end.
+ SetShellVarContext all
+ ${UpdateShortcutsBranding}
+ ${If} ${AtLeastWin8}
+ ${TouchStartMenuShortcut}
+ ${EndIf}
+ Call FixShortcutAppModelIDs
+ SetShellVarContext current
+ ${UpdateShortcutsBranding}
+ ${If} ${AtLeastWin8}
+ ${TouchStartMenuShortcut}
+ ${EndIf}
+ Call FixShortcutAppModelIDs
+ ${If} $TmpVal == "HKLM"
+ SetShellVarContext all
+ ${ElseIf} $TmpVal == "HKCU"
+ SetShellVarContext current
+ ${EndIf}
+
+ ${RemoveDeprecatedKeys}
+ ${Set32to64DidMigrateReg}
+
+ ${SetAppKeys}
+ ${FixClassKeys}
+ ${SetUninstallKeys}
+ ${If} $TmpVal == "HKLM"
+ ${SetStartMenuInternet} HKLM
+ ${ElseIf} $TmpVal == "HKCU"
+ ${SetStartMenuInternet} HKCU
+ ${EndIf}
+
+ ; Remove files that may be left behind by the application in the
+ ; VirtualStore directory.
+ ${CleanVirtualStore}
+
+ ${RemoveDeprecatedFiles}
+
+ ; Fix the distribution.ini file if applicable
+ ${FixDistributionsINI}
+
+ ; https://bugzilla.mozilla.org/show_bug.cgi?id=1616355
+ ; Migrate postSigningData file if present, and if it doesn't already exist.
+ ${GetLocalAppDataFolder} $0
+ ${If} ${FileExists} "$INSTDIR\postSigningData"
+ ; If it already exists, just delete the appdata one.
+ ; It's possible this was for a different install, but it's impossible to
+ ; know for sure, so we may as well just get rid of it.
+ Delete /REBOOTOK "$0\Mozilla\Firefox\postSigningData"
+ ${Else}
+ ${If} ${FileExists} "$0\Mozilla\Firefox\postSigningData"
+ Rename "$0\Mozilla\Firefox\postSigningData" "$INSTDIR\postSigningData"
+ ${EndIf}
+ ${EndIf}
+
+ RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}"
+
+ ; Register AccessibleHandler.dll with COM (this requires write access to HKLM)
+ ${RegisterAccessibleHandler}
+
+ ; Register AccessibleMarshal.dll with COM (this requires write access to HKLM)
+ ${RegisterAccessibleMarshal}
+
+ ; Record the Windows Error Reporting module
+ WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\RuntimeExceptionHelperModules" "$INSTDIR\mozwer.dll" 0
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+ Call IsUserAdmin
+ Pop $R0
+ ${If} $R0 == "true"
+ ; Only proceed if we have HKLM write access
+ ${AndIf} $TmpVal == "HKLM"
+ ; We check to see if the maintenance service install was already attempted.
+ ; Since the Maintenance service can be installed either x86 or x64,
+ ; always use the 64-bit registry for checking if an attempt was made.
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView 64
+ ${EndIf}
+ ReadRegDWORD $5 HKLM "Software\Mozilla\MaintenanceService" "Attempted"
+ ClearErrors
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView lastused
+ ${EndIf}
+
+ ; Add the registry keys for allowed certificates.
+ ${AddMaintCertKeys}
+
+ ; If the maintenance service is already installed, do nothing.
+ ; The maintenance service will launch:
+ ; maintenanceservice_installer.exe /Upgrade to upgrade the maintenance
+ ; service if necessary. If the update was done from updater.exe without
+ ; the service (i.e. service is failing), updater.exe will do the update of
+ ; the service. The reasons we do not do it here is because we don't want
+ ; to have to prompt for limited user accounts when the service isn't used
+ ; and we currently call the PostUpdate twice, once for the user and once
+ ; for the SYSTEM account. Also, this would stop the maintenance service
+ ; and we need a return result back to the service when run that way.
+ ${If} $5 == ""
+ ; An install of maintenance service was never attempted.
+ ; We know we are an Admin and that we have write access into HKLM
+ ; based on the above checks, so attempt to just run the EXE.
+ ; In the worst case, in case there is some edge case with the
+ ; IsAdmin check and the permissions check, the maintenance service
+ ; will just fail to be attempted to be installed.
+ nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""
+ ${EndIf}
+ ${EndIf}
+!endif
+
+!ifdef MOZ_LAUNCHER_PROCESS
+ ${ResetLauncherProcessDefaults}
+!endif
+
+ ${If} ${AtLeastWin10}
+ ${WriteToastNotificationRegistration} $TmpVal
+ ${EndIf}
+
+; Make sure the scheduled task registration for the default browser agent gets
+; updated, but only if we're not the instance of PostUpdate that was started
+; by the service, because this needs to run as the actual user. Also, don't do
+; that if the installer was told not to register the agent task at all.
+!ifdef MOZ_DEFAULT_BROWSER_AGENT
+${If} $TmpVal == "HKCU"
+ ClearErrors
+ ReadRegDWORD $0 HKCU "Software\Mozilla\${AppName}\Installer\$AppUserModelID" \
+ "DidRegisterDefaultBrowserAgent"
+ ${If} $0 != 0
+ ${OrIf} ${Errors}
+ ExecWait '"$INSTDIR\default-browser-agent.exe" register-task $AppUserModelID'
+ ${EndIf}
+${ElseIf} $TmpVal == "HKLM"
+ ; If we're the privileged PostUpdate, make sure that the unprivileged one
+ ; will have permission to create a task by clearing out the old one first.
+ ExecWait '"$INSTDIR\default-browser-agent.exe" unregister-task $AppUserModelID'
+${EndIf}
+!endif
+
+${RemoveDefaultBrowserAgentShortcut}
+!macroend
+!define PostUpdate "!insertmacro PostUpdate"
+
+; Update the last modified time on the Start Menu shortcut, so that its icon
+; gets refreshed. Should be called on Win8+ after UpdateShortcutBranding.
+!macro TouchStartMenuShortcut
+ ${If} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ FileOpen $0 "$SMPROGRAMS\${BrandShortName}.lnk" a
+ ${IfNot} ${Errors}
+ System::Call '*(i, i) p .r1'
+ System::Call 'kernel32::GetSystemTimeAsFileTime(p r1)'
+ System::Call 'kernel32::SetFileTime(p r0, i 0, i 0, p r1) i .r2'
+ System::Free $1
+ FileClose $0
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define TouchStartMenuShortcut "!insertmacro TouchStartMenuShortcut"
+
+!macro AddPrivateBrowsingShortcut
+ ${IfNot} ${FileExists} "$SMPROGRAMS\$(PRIVATE_BROWSING_SHORTCUT_TITLE).lnk"
+ CreateShortcut "$SMPROGRAMS\$(PRIVATE_BROWSING_SHORTCUT_TITLE).lnk" "$INSTDIR\${PrivateBrowsingEXE}" "" "$INSTDIR\${PrivateBrowsingEXE}" ${IDI_PBICON_PB_EXE_ZERO_BASED}
+ ShellLink::SetShortcutWorkingDirectory "$SMPROGRAMS\$(PRIVATE_BROWSING_SHORTCUT_TITLE).lnk" "$INSTDIR"
+ ShellLink::SetShortcutDescription "$SMPROGRAMS\$(PRIVATE_BROWSING_SHORTCUT_TITLE).lnk" "$(PRIVATE_BROWSING_SHORTCUT_TITLE)"
+ ApplicationID::Set "$SMPROGRAMS\$(PRIVATE_BROWSING_SHORTCUT_TITLE).lnk" "$AppUserModelID;PrivateBrowsingAUMID" "true"
+ ${LogStartMenuShortcut} "$(PRIVATE_BROWSING_SHORTCUT_TITLE).lnk"
+ ${EndIf}
+!macroend
+!define AddPrivateBrowsingShortcut "!insertmacro AddPrivateBrowsingShortcut"
+
+!macro SetAsDefaultAppGlobal
+ ${RemoveDeprecatedKeys} ; Does not use SHCTX
+
+ SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
+ ${SetHandlers} ; Uses SHCTX
+ ${SetStartMenuInternet} "HKLM"
+ ${FixShellIconHandler} "HKLM"
+ ${ShowShortcuts}
+!macroend
+!define SetAsDefaultAppGlobal "!insertmacro SetAsDefaultAppGlobal"
+
+; Removes shortcuts for this installation. This should also remove the
+; application from Open With for the file types the application handles
+; (bug 370480).
+!macro HideShortcuts
+ ; Find the correct registry path to clear IconsVisible.
+ StrCpy $R1 "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\InstallInfo"
+ ReadRegDWORD $0 HKLM "$R1" "ShowIconsCommand"
+ ${If} ${Errors}
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $0
+ StrCpy $R1 "Software\Clients\StartMenuInternet\$0\InstallInfo"
+ ${EndIf}
+ WriteRegDWORD HKLM "$R1" "IconsVisible" 0
+ ${If} ${AtLeastWin8}
+ WriteRegDWORD HKCU "$R1" "IconsVisible" 0
+ ${EndIf}
+
+ SetShellVarContext all ; Set $DESKTOP to All Users
+ ${Unless} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ SetShellVarContext current ; Set $DESKTOP to the current user's desktop
+ ${EndUnless}
+
+ ${If} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ ShellLink::GetShortCutArgs "$DESKTOP\${BrandShortName}.lnk"
+ Pop $0
+ ${If} "$0" == ""
+ ShellLink::GetShortCutTarget "$DESKTOP\${BrandShortName}.lnk"
+ Pop $0
+ ${GetLongPath} "$0" $0
+ ${If} "$0" == "$INSTDIR\${FileMainEXE}"
+ Delete "$DESKTOP\${BrandShortName}.lnk"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+ SetShellVarContext all ; Set $SMPROGRAMS to All Users
+ ${Unless} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ SetShellVarContext current ; Set $SMPROGRAMS to the current user's Start
+ ; Menu Programs directory
+ ${EndUnless}
+
+ ${If} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ ShellLink::GetShortCutArgs "$SMPROGRAMS\${BrandShortName}.lnk"
+ Pop $0
+ ${If} "$0" == ""
+ ShellLink::GetShortCutTarget "$SMPROGRAMS\${BrandShortName}.lnk"
+ Pop $0
+ ${GetLongPath} "$0" $0
+ ${If} "$0" == "$INSTDIR\${FileMainEXE}"
+ Delete "$SMPROGRAMS\${BrandShortName}.lnk"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+ ${If} ${FileExists} "$QUICKLAUNCH\${BrandShortName}.lnk"
+ ShellLink::GetShortCutArgs "$QUICKLAUNCH\${BrandShortName}.lnk"
+ Pop $0
+ ${If} "$0" == ""
+ ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandShortName}.lnk"
+ Pop $0
+ ${GetLongPath} "$0" $0
+ ${If} "$0" == "$INSTDIR\${FileMainEXE}"
+ Delete "$QUICKLAUNCH\${BrandShortName}.lnk"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define HideShortcuts "!insertmacro HideShortcuts"
+
+; Adds shortcuts for this installation. This should also add the application
+; to Open With for the file types the application handles (bug 370480).
+!macro ShowShortcuts
+ ; Find the correct registry path to set IconsVisible.
+ StrCpy $R1 "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\InstallInfo"
+ ReadRegDWORD $0 HKLM "$R1" "ShowIconsCommand"
+ ${If} ${Errors}
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $0
+ StrCpy $R1 "Software\Clients\StartMenuInternet\$0\InstallInfo"
+ ${EndIf}
+ WriteRegDWORD HKLM "$R1" "IconsVisible" 1
+ ${If} ${AtLeastWin8}
+ WriteRegDWORD HKCU "$R1" "IconsVisible" 1
+ ${EndIf}
+
+ SetShellVarContext all ; Set $DESKTOP to All Users
+ ${Unless} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ CreateShortCut "$DESKTOP\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandShortName}.lnk" "$INSTDIR"
+ ${If} ${AtLeastWin7}
+ ${AndIf} "$AppUserModelID" != ""
+ ApplicationID::Set "$DESKTOP\${BrandShortName}.lnk" "$AppUserModelID" "true"
+ ${EndIf}
+ ${Else}
+ SetShellVarContext current ; Set $DESKTOP to the current user's desktop
+ ${Unless} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ CreateShortCut "$DESKTOP\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${If} ${AtLeastWin7}
+ ${AndIf} "$AppUserModelID" != ""
+ ApplicationID::Set "$DESKTOP\${BrandShortName}.lnk" "$AppUserModelID" "true"
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+ ${EndIf}
+ ${EndUnless}
+
+ SetShellVarContext all ; Set $SMPROGRAMS to All Users
+ ${Unless} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ CreateShortCut "$SMPROGRAMS\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$SMPROGRAMS\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${If} ${AtLeastWin7}
+ ${AndIf} "$AppUserModelID" != ""
+ ApplicationID::Set "$SMPROGRAMS\${BrandShortName}.lnk" "$AppUserModelID" "true"
+ ${EndIf}
+ ${Else}
+ SetShellVarContext current ; Set $SMPROGRAMS to the current user's Start
+ ; Menu Programs directory
+ ${Unless} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ CreateShortCut "$SMPROGRAMS\${BrandShortName}.lnk" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$SMPROGRAMS\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$SMPROGRAMS\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${If} ${AtLeastWin7}
+ ${AndIf} "$AppUserModelID" != ""
+ ApplicationID::Set "$SMPROGRAMS\${BrandShortName}.lnk" "$AppUserModelID" "true"
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+ ${EndIf}
+ ${EndUnless}
+
+ ; Windows 7 doesn't use the QuickLaunch directory
+ ${Unless} ${AtLeastWin7}
+ ${AndUnless} ${FileExists} "$QUICKLAUNCH\${BrandShortName}.lnk"
+ CreateShortCut "$QUICKLAUNCH\${BrandShortName}.lnk" \
+ "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$QUICKLAUNCH\${BrandShortName}.lnk"
+ ShellLink::SetShortCutWorkingDirectory "$QUICKLAUNCH\${BrandShortName}.lnk" \
+ "$INSTDIR"
+ ${EndIf}
+ ${EndUnless}
+!macroend
+!define ShowShortcuts "!insertmacro ShowShortcuts"
+
+; Update the branding name on all shortcuts our installer created
+; to convert from BrandFullName (which is what we used to name shortcuts)
+; to BrandShortName (which is what we now name shortcuts). We only rename
+; desktop and start menu shortcuts, because touching taskbar pins often
+; (but inconsistently) triggers various broken behaviors in the shell.
+; This assumes SHCTX is set correctly.
+!macro UpdateShortcutsBranding
+ ${UpdateOneShortcutBranding} "STARTMENU" "$SMPROGRAMS"
+ ${UpdateOneShortcutBranding} "DESKTOP" "$DESKTOP"
+!macroend
+!define UpdateShortcutsBranding "!insertmacro UpdateShortcutsBranding"
+
+!macro UpdateOneShortcutBranding LOG_SECTION SHORTCUT_DIR
+ ; Only try to rename the shortcuts found in the shortcuts log, to avoid
+ ; blowing away a name that the user created.
+ ${GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R9
+ ${If} ${FileExists} "$R9"
+ ClearErrors
+ ; The shortcuts log contains a numbered list of entries for each section,
+ ; but we never actually create more than one.
+ ReadINIStr $R8 "$R9" "${LOG_SECTION}" "Shortcut0"
+ ${IfNot} ${Errors}
+ ${If} ${FileExists} "${SHORTCUT_DIR}\$R8"
+ ShellLink::GetShortCutTarget "${SHORTCUT_DIR}\$R8"
+ Pop $R7
+ ${GetLongPath} "$R7" $R7
+ ${If} $R7 == "$INSTDIR\${FileMainEXE}"
+ ${AndIf} $R8 != "${BrandShortName}.lnk"
+ ${AndIfNot} ${FileExists} "${SHORTCUT_DIR}\${BrandShortName}.lnk"
+ ClearErrors
+ Rename "${SHORTCUT_DIR}\$R8" "${SHORTCUT_DIR}\${BrandShortName}.lnk"
+ ${IfNot} ${Errors}
+ ; Update the shortcut log manually instead of calling LogShortcut
+ ; because it would add a Shortcut1 entry, and we really do want to
+ ; overwrite the existing entry 0, since we just renamed the file.
+ WriteINIStr "$R9" "${LOG_SECTION}" "Shortcut0" \
+ "${BrandShortName}.lnk"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define UpdateOneShortcutBranding "!insertmacro UpdateOneShortcutBranding"
+
+; Remove a shortcut unintentionally added by the default browser agent (bug 1672957, 1681207)
+!macro RemoveDefaultBrowserAgentShortcut
+ Push $0
+ Push $1
+ Push $2
+ Push $3
+
+ ; Get the current user's Start Menu Programs.
+ ${GetProgramsFolder} $1
+
+ ; The shortcut would have been named MOZ_BASE_NAME regardless of branding.
+ ; According to defines.nsi.in AppName should match application.ini, and application.ini.in sets
+ ; [App] Name from MOZ_BASE_NAME.
+ StrCpy $1 "$1\${AppName}.lnk"
+ ShellLink::GetShortCutTarget $1
+ Pop $0
+
+ ; ShellLink::GetShortCutTarget, and the underlying IShellLink::GetPath(), have an issue
+ ; where "C:\Program Files" becomes "C:\Program Files (x86)" in some cases.
+ ; It should be OK to remove the shortcut (which matches our app name) even if it isn't from this
+ ; install, as long as the file name portion of the target path matches.
+ StrCpy $2 "\default-browser-agent.exe"
+ StrLen $3 $2
+ ; Select the substring to match from the end of the target path.
+ StrCpy $0 $0 $3 -$3
+ ${If} $0 == $2
+ Delete $1
+ ${EndIf}
+
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+!macroend
+!define RemoveDefaultBrowserAgentShortcut "!insertmacro RemoveDefaultBrowserAgentShortcut"
+
+!macro AddAssociationIfNoneExist FILE_TYPE KEY
+ ClearErrors
+ EnumRegKey $7 HKCR "${FILE_TYPE}" 0
+ ${If} ${Errors}
+ WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}" "" ${KEY}
+ ${EndIf}
+ WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}\OpenWithProgids" ${KEY} ""
+!macroend
+!define AddAssociationIfNoneExist "!insertmacro AddAssociationIfNoneExist"
+
+; Adds the protocol and file handler registry entries for making Firefox the
+; default handler (uses SHCTX).
+!macro SetHandlers
+ ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
+
+ ; See if we're using path hash suffixed registry keys for this install.
+ StrCpy $5 ""
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $2
+ ReadRegStr $0 SHCTX "Software\Clients\StartMenuInternet\$2\DefaultIcon" ""
+ StrCpy $0 $0 -2
+ ${If} $0 != $8
+ StrCpy $5 "-$AppUserModelID"
+ ${EndIf}
+
+ StrCpy $0 "SOFTWARE\Classes"
+ StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
+
+ ; Associate the file handlers with FirefoxHTML, if they aren't already.
+ ReadRegStr $6 SHCTX "$0\.htm" ""
+ ${WordFind} "$6" "-" "+1{" $6
+ ${If} "$6" != "FirefoxHTML"
+ WriteRegStr SHCTX "$0\.htm" "" "FirefoxHTML$5"
+ ${EndIf}
+
+ ReadRegStr $6 SHCTX "$0\.html" ""
+ ${WordFind} "$6" "-" "+1{" $6
+ ${If} "$6" != "FirefoxHTML"
+ WriteRegStr SHCTX "$0\.html" "" "FirefoxHTML$5"
+ ${EndIf}
+
+ ReadRegStr $6 SHCTX "$0\.shtml" ""
+ ${WordFind} "$6" "-" "+1{" $6
+ ${If} "$6" != "FirefoxHTML"
+ WriteRegStr SHCTX "$0\.shtml" "" "FirefoxHTML$5"
+ ${EndIf}
+
+ ReadRegStr $6 SHCTX "$0\.xht" ""
+ ${WordFind} "$6" "-" "+1{" $6
+ ${If} "$6" != "FirefoxHTML"
+ WriteRegStr SHCTX "$0\.xht" "" "FirefoxHTML$5"
+ ${EndIf}
+
+ ReadRegStr $6 SHCTX "$0\.xhtml" ""
+ ${WordFind} "$6" "-" "+1{" $6
+ ${If} "$6" != "FirefoxHTML"
+ WriteRegStr SHCTX "$0\.xhtml" "" "FirefoxHTML$5"
+ ${EndIf}
+
+
+ ; Keep this list synchronized with
+ ; https://searchfox.org/mozilla-central/source/browser/installer/windows/msix/AppxManifest.xml.in.
+ ; and `os.environment.launched_to_handle` and `os.environment.invoked_to_handle` telemetry in
+ ; https://searchfox.org/mozilla-central/source/browser/components/BrowserContentHandler.sys.mjs.
+ ${AddAssociationIfNoneExist} ".oga" "FirefoxHTML$5"
+ ${AddAssociationIfNoneExist} ".ogg" "FirefoxHTML$5"
+ ${AddAssociationIfNoneExist} ".ogv" "FirefoxHTML$5"
+ ${AddAssociationIfNoneExist} ".webm" "FirefoxHTML$5"
+ ${AddAssociationIfNoneExist} ".svg" "FirefoxHTML$5"
+ ${AddAssociationIfNoneExist} ".webp" "FirefoxHTML$5"
+ ${AddAssociationIfNoneExist} ".avif" "FirefoxHTML$5"
+
+ ${AddAssociationIfNoneExist} ".pdf" "FirefoxPDF$5"
+
+ ; An empty string is used for the 5th param because FirefoxHTML- is not a
+ ; protocol handler. Ditto for FirefoxPDF-.
+ ${AddDisabledDDEHandlerValues} "FirefoxHTML$5" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} HTML Document" ""
+
+ ${AddDisabledDDEHandlerValues} "FirefoxPDF$5" "$2" "$8,${IDI_DOCUMENT_PDF_ZERO_BASED}" \
+ "${AppRegName} PDF Document" ""
+
+ ${AddDisabledDDEHandlerValues} "FirefoxURL$5" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "${AppRegName} URL" \
+ "true"
+ ; An empty string is used for the 4th & 5th params because the following
+ ; protocol handlers already have a display name and the additional keys
+ ; required for a protocol handler.
+ ${AddDisabledDDEHandlerValues} "http" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" ""
+ ${AddDisabledDDEHandlerValues} "https" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" ""
+ ${AddDisabledDDEHandlerValues} "mailto" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" ""
+!macroend
+!define SetHandlers "!insertmacro SetHandlers"
+
+!macro WriteApplicationsSupportedType RegKey Type
+ WriteRegStr ${RegKey} "Software\Classes\Applications\${FileMainEXE}\SupportedTypes" "${Type}" ""
+!macroend
+!define WriteApplicationsSupportedType "!insertmacro WriteApplicationsSupportedType"
+
+; Adds the HKLM\Software\Clients\StartMenuInternet\Firefox-[pathhash] registry
+; entries (does not use SHCTX).
+;
+; The values for StartMenuInternet are only valid under HKLM and there can only
+; be one installation registerred under StartMenuInternet per application since
+; the key name is derived from the main application executable.
+;
+; In Windows 8 this changes slightly, you can store StartMenuInternet entries in
+; HKCU. The icon in start menu for StartMenuInternet is deprecated as of Win7,
+; but the subkeys are what's important. Control panel default programs looks
+; for them only in HKLM pre win8.
+;
+; The StartMenuInternet key and friends are documented at
+; https://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=vs.85).aspx
+;
+; This function also writes our RegisteredApplications entry, which gets us
+; listed in the Settings app's default browser options on Windows 8+, and in
+; Set Program Access and Defaults on earlier versions.
+!macro SetStartMenuInternet RegKey
+ ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
+ ${GetLongPath} "$INSTDIR\uninstall\helper.exe" $7
+
+ ; If we already have keys at the old FIREFOX.EXE path, then just update those.
+ ; We have to be careful to update the existing keys in place so that we don't
+ ; create duplicate keys for the same installation, or cause Windows to think
+ ; something "suspicious" has happened and it should reset the default browser.
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $1
+ ReadRegStr $0 ${RegKey} "Software\Clients\StartMenuInternet\$1\DefaultIcon" ""
+ StrCpy $0 $0 -2
+ ${If} $0 != $8
+ StrCpy $1 "${AppRegName}-$AppUserModelID"
+ StrCpy $2 "-$AppUserModelID"
+ ${Else}
+ StrCpy $2 ""
+ ${EndIf}
+ StrCpy $0 "Software\Clients\StartMenuInternet\$1"
+
+ WriteRegStr ${RegKey} "$0" "" "${BrandFullName}"
+
+ WriteRegStr ${RegKey} "$0\DefaultIcon" "" "$8,${IDI_APPICON_ZERO_BASED}"
+
+ ; The Reinstall Command is defined at
+ ; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_adv/registeringapps.asp
+ WriteRegStr ${RegKey} "$0\InstallInfo" "HideIconsCommand" "$\"$7$\" /HideShortcuts"
+ WriteRegStr ${RegKey} "$0\InstallInfo" "ShowIconsCommand" "$\"$7$\" /ShowShortcuts"
+ WriteRegStr ${RegKey} "$0\InstallInfo" "ReinstallCommand" "$\"$7$\" /SetAsDefaultAppGlobal"
+ WriteRegDWORD ${RegKey} "$0\InstallInfo" "IconsVisible" 1
+
+ WriteRegStr ${RegKey} "$0\shell\open\command" "" "$\"$8$\""
+
+ WriteRegStr ${RegKey} "$0\shell\properties" "" "$(CONTEXT_OPTIONS)"
+ WriteRegStr ${RegKey} "$0\shell\properties\command" "" "$\"$8$\" -preferences"
+
+ WriteRegStr ${RegKey} "$0\shell\safemode" "" "$(CONTEXT_SAFE_MODE)"
+ WriteRegStr ${RegKey} "$0\shell\safemode\command" "" "$\"$8$\" -safe-mode"
+
+ ; Capabilities registry keys
+ WriteRegStr ${RegKey} "$0\Capabilities" "ApplicationDescription" "$(REG_APP_DESC)"
+ WriteRegStr ${RegKey} "$0\Capabilities" "ApplicationIcon" "$8,${IDI_APPICON_ZERO_BASED}"
+ WriteRegStr ${RegKey} "$0\Capabilities" "ApplicationName" "${BrandShortName}"
+
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".htm" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".html" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".shtml" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".xht" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".xhtml" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".svg" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".webp" "FirefoxHTML$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".avif" "FirefoxHTML$2"
+
+ WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".pdf" "FirefoxPDF$2"
+
+ WriteRegStr ${RegKey} "$0\Capabilities\StartMenu" "StartMenuInternet" "$1"
+
+ ; In the past, we supported ftp. Since we don't delete and re-create the
+ ; entire key, we need to remove any existing registration.
+ DeleteRegValue ${RegKey} "$0\Capabilities\URLAssociations" "ftp"
+
+ WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "http" "FirefoxURL$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "https" "FirefoxURL$2"
+ WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "mailto" "FirefoxURL$2"
+
+ WriteRegStr ${RegKey} "Software\RegisteredApplications" "$1" "$0\Capabilities"
+
+ ; This key would be created by the Open With dialog when a user creates an
+ ; association for us with a file type that we haven't registered as a handler
+ ; for. We need to preemptively create it ourselves so that we can control the
+ ; command line that's used to launch us in that situation. If it's too late
+ ; and one already exists, then we need to edit its command line to make sure
+ ; it contains the -osint flag.
+ ReadRegStr $6 ${RegKey} "Software\Classes\Applications\${FileMainEXE}\shell\open\command" ""
+ ${If} $6 != ""
+ ${GetPathFromString} "$6" $6
+ WriteRegStr ${RegKey} "Software\Classes\Applications\${FileMainEXE}\shell\open\command" \
+ "" "$\"$6$\" -osint -url $\"%1$\""
+ ${Else}
+ WriteRegStr ${RegKey} "Software\Classes\Applications\${FileMainEXE}\shell\open\command" \
+ "" "$\"$8$\" -osint -url $\"%1$\""
+ ; Make sure files associated this way use the document icon instead of the
+ ; application icon.
+ WriteRegStr ${RegKey} "Software\Classes\Applications\${FileMainEXE}\DefaultIcon" \
+ "" "$8,${IDI_DOCUMENT_ZERO_BASED}"
+ ; If we're going to create this key at all, we also need to list our supported
+ ; file types in it, because otherwise we'll be shown as a suggestion for every
+ ; single file type, whether we support it in any way or not.
+ ; We take a more expansive approach to the set of file types registered
+ ; here compared to elsewhere because this key is interpreted by the OS as
+ ; containing every file type that we can possibly open, so if something
+ ; isn't listed it assumes we can't open it and hides us from e.g. the Open
+ ; With context menu, even if the user has tried to add us there manually.
+ ; The list here was derived from the file /layout/build/components.conf,
+ ; filtered down to only those types which make sense to open on their own
+ ; in Firefox, basically meaning that plain text file types were left out,
+ ; but not JSON or XML types because we have specific viewers for those.
+ ${WriteApplicationsSupportedType} ${RegKey} ".apng"
+ ${WriteApplicationsSupportedType} ${RegKey} ".bmp"
+ ${WriteApplicationsSupportedType} ${RegKey} ".flac"
+ ${WriteApplicationsSupportedType} ${RegKey} ".gif"
+ ${WriteApplicationsSupportedType} ${RegKey} ".htm"
+ ${WriteApplicationsSupportedType} ${RegKey} ".html"
+ ${WriteApplicationsSupportedType} ${RegKey} ".ico"
+ ${WriteApplicationsSupportedType} ${RegKey} ".jfif"
+ ${WriteApplicationsSupportedType} ${RegKey} ".jpeg"
+ ${WriteApplicationsSupportedType} ${RegKey} ".jpg"
+ ${WriteApplicationsSupportedType} ${RegKey} ".json"
+ ${WriteApplicationsSupportedType} ${RegKey} ".m4a"
+ ${WriteApplicationsSupportedType} ${RegKey} ".mp3"
+ ${WriteApplicationsSupportedType} ${RegKey} ".oga"
+ ${WriteApplicationsSupportedType} ${RegKey} ".ogg"
+ ${WriteApplicationsSupportedType} ${RegKey} ".ogv"
+ ${WriteApplicationsSupportedType} ${RegKey} ".opus"
+ ${WriteApplicationsSupportedType} ${RegKey} ".pdf"
+ ${WriteApplicationsSupportedType} ${RegKey} ".pjpeg"
+ ${WriteApplicationsSupportedType} ${RegKey} ".pjp"
+ ${WriteApplicationsSupportedType} ${RegKey} ".png"
+ ${WriteApplicationsSupportedType} ${RegKey} ".rdf"
+ ${WriteApplicationsSupportedType} ${RegKey} ".shtml"
+ ${WriteApplicationsSupportedType} ${RegKey} ".svg"
+ ${WriteApplicationsSupportedType} ${RegKey} ".webm"
+ ${WriteApplicationsSupportedType} ${RegKey} ".webp"
+ ${WriteApplicationsSupportedType} ${RegKey} ".avif"
+ ${WriteApplicationsSupportedType} ${RegKey} ".xht"
+ ${WriteApplicationsSupportedType} ${RegKey} ".xhtml"
+ ${WriteApplicationsSupportedType} ${RegKey} ".xml"
+ ${EndIf}
+!macroend
+!define SetStartMenuInternet "!insertmacro SetStartMenuInternet"
+
+; Add registry keys to support the Firefox 32 bit to 64 bit migration. These
+; registry entries are not removed on uninstall at this time. After the Firefox
+; 32 bit to 64 bit migration effort is completed these registry entries can be
+; removed during install, post update, and uninstall.
+!macro Set32to64DidMigrateReg
+ ${GetLongPath} "$INSTDIR" $1
+ ; These registry keys are always in the 32 bit hive since they are never
+ ; needed by a Firefox 64 bit install unless it has been updated from Firefox
+ ; 32 bit.
+ SetRegView 32
+
+!ifdef HAVE_64BIT_BUILD
+
+ ; Running Firefox 64 bit on Windows 64 bit
+ ClearErrors
+ ReadRegDWORD $2 HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
+ ; If there were no errors then the system was updated from Firefox 32 bit to
+ ; Firefox 64 bit and if the value is already 1 then the registry value has
+ ; already been updated in the HKLM registry.
+ ${IfNot} ${Errors}
+ ${AndIf} $2 != 1
+ ClearErrors
+ WriteRegDWORD HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 1
+ ${If} ${Errors}
+ ; There was an error writing to HKLM so just write it to HKCU
+ WriteRegDWORD HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 1
+ ${Else}
+ ; This will delete the value from HKCU if it exists
+ DeleteRegValue HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
+ ${EndIf}
+ ${EndIf}
+
+ ClearErrors
+ ReadRegDWORD $2 HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
+ ; If there were no errors then the system was updated from Firefox 32 bit to
+ ; Firefox 64 bit and if the value is already 1 then the registry value has
+ ; already been updated in the HKCU registry.
+ ${IfNot} ${Errors}
+ ${AndIf} $2 != 1
+ WriteRegDWORD HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 1
+ ${EndIf}
+
+!else
+
+ ; Running Firefox 32 bit
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ ; Running Firefox 32 bit on a Windows 64 bit system
+ ClearErrors
+ ReadRegDWORD $2 HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
+ ; If there were errors the value doesn't exist yet.
+ ${If} ${Errors}
+ ClearErrors
+ WriteRegDWORD HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 0
+ ; If there were errors write the value in HKCU.
+ ${If} ${Errors}
+ WriteRegDWORD HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 0
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+!endif
+
+ ClearErrors
+ SetRegView lastused
+!macroend
+!define Set32to64DidMigrateReg "!insertmacro Set32to64DidMigrateReg"
+
+; The IconHandler reference for FirefoxHTML can end up in an inconsistent state
+; due to changes not being detected by the IconHandler for side by side
+; installs (see bug 268512). The symptoms can be either an incorrect icon or no
+; icon being displayed for files associated with Firefox (does not use SHCTX).
+!macro FixShellIconHandler RegKey
+ ; Find the correct key to update, either FirefoxHTML or FirefoxHTML-[PathHash]
+ StrCpy $3 "FirefoxHTML-$AppUserModelID"
+ ClearErrors
+ ReadRegStr $0 ${RegKey} "Software\Classes\$3\DefaultIcon" ""
+ ${If} ${Errors}
+ StrCpy $3 "FirefoxHTML"
+ ${EndIf}
+
+ ClearErrors
+ ReadRegStr $1 ${RegKey} "Software\Classes\$3\ShellEx\IconHandler" ""
+ ${Unless} ${Errors}
+ ReadRegStr $1 ${RegKey} "Software\Classes\$3\DefaultIcon" ""
+ ${GetLongPath} "$INSTDIR\${FileMainEXE}" $2
+ ${If} "$1" != "$2,${IDI_DOCUMENT_ZERO_BASED}"
+ WriteRegStr ${RegKey} "Software\Classes\$3\DefaultIcon" "" "$2,${IDI_DOCUMENT_ZERO_BASED}"
+ ${EndIf}
+ ${EndUnless}
+!macroend
+!define FixShellIconHandler "!insertmacro FixShellIconHandler"
+
+; Add Software\Mozilla\ registry entries (uses SHCTX).
+!macro SetAppKeys
+ ; Check if this is an ESR release and if so add registry values so it is
+ ; possible to determine that this is an ESR install (bug 726781).
+ ClearErrors
+ ${WordFind} "${UpdateChannel}" "esr" "E#" $3
+ ${If} ${Errors}
+ StrCpy $3 ""
+ ${Else}
+ StrCpy $3 " ESR"
+ ${EndIf}
+
+ ${GetLongPath} "$INSTDIR" $8
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion}$3 (${ARCH} ${AB_CD})\Main"
+ ${WriteRegStr2} $TmpVal "$0" "Install Directory" "$8" 0
+ ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$8\${FileMainEXE}" 0
+
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion}$3 (${ARCH} ${AB_CD})\Uninstall"
+ ${WriteRegStr2} $TmpVal "$0" "Description" "${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})" 0
+
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion}$3 (${ARCH} ${AB_CD})"
+ ${WriteRegStr2} $TmpVal "$0" "" "${AppVersion}$3 (${ARCH} ${AB_CD})" 0
+ ${If} "$3" == ""
+ DeleteRegValue SHCTX "$0" "ESR"
+ ${Else}
+ ${WriteRegDWORD2} $TmpVal "$0" "ESR" 1 0
+ ${EndIf}
+
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}$3\bin"
+ ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$8\${FileMainEXE}" 0
+
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}$3\extensions"
+ ${WriteRegStr2} $TmpVal "$0" "Components" "$8\components" 0
+ ${WriteRegStr2} $TmpVal "$0" "Plugins" "$8\plugins" 0
+
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}$3"
+ ${WriteRegStr2} $TmpVal "$0" "GeckoVer" "${GREVersion}" 0
+ ${If} "$3" == ""
+ DeleteRegValue SHCTX "$0" "ESR"
+ ${Else}
+ ${WriteRegDWORD2} $TmpVal "$0" "ESR" 1 0
+ ${EndIf}
+
+ StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}$3"
+ ${WriteRegStr2} $TmpVal "$0" "" "${GREVersion}" 0
+ ${WriteRegStr2} $TmpVal "$0" "CurrentVersion" "${AppVersion}$3 (${ARCH} ${AB_CD})" 0
+!macroend
+!define SetAppKeys "!insertmacro SetAppKeys"
+
+; Add uninstall registry entries. This macro tests for write access to determine
+; if the uninstall keys should be added to HKLM or HKCU.
+!macro SetUninstallKeys
+ ; Check if this is an ESR release and if so add registry values so it is
+ ; possible to determine that this is an ESR install (bug 726781).
+ ClearErrors
+ ${WordFind} "${UpdateChannel}" "esr" "E#" $3
+ ${If} ${Errors}
+ StrCpy $3 ""
+ ${Else}
+ StrCpy $3 " ESR"
+ ${EndIf}
+
+ StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})"
+
+ StrCpy $2 ""
+ ClearErrors
+ WriteRegStr HKLM "$0" "${BrandShortName}InstallerTest" "Write Test"
+ ${If} ${Errors}
+ ; If the uninstall keys already exist in HKLM don't create them in HKCU
+ ClearErrors
+ ReadRegStr $2 "HKLM" $0 "DisplayName"
+ ${If} $2 == ""
+ ; Otherwise we don't have any keys for this product in HKLM so proceeed
+ ; to create them in HKCU. Better handling for this will be done in:
+ ; Bug 711044 - Better handling for 2 uninstall icons
+ StrCpy $1 "HKCU"
+ SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
+ ${EndIf}
+ ClearErrors
+ ${Else}
+ StrCpy $1 "HKLM"
+ SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
+ DeleteRegValue HKLM "$0" "${BrandShortName}InstallerTest"
+ ${EndIf}
+
+ ${If} $2 == ""
+ ${GetLongPath} "$INSTDIR" $8
+
+ ; Write the uninstall registry keys
+ ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})" 0
+ ${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},${IDI_APPICON_ZERO_BASED}" 0
+ ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal}$3 (${ARCH} ${AB_CD})" 0
+ ${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0
+ ${WriteRegStr2} $1 "$0" "HelpLink" "${HelpLink}" 0
+ ${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0
+ ${WriteRegStr2} $1 "$0" "Publisher" "Mozilla" 0
+ ${WriteRegStr2} $1 "$0" "UninstallString" "$\"$8\uninstall\helper.exe$\"" 0
+ DeleteRegValue SHCTX "$0" "URLInfoAbout"
+; Don't add URLUpdateInfo which is the release notes url except for the release
+; and esr channels since nightly, aurora, and beta do not have release notes.
+; Note: URLUpdateInfo is only defined in the official branding.nsi.
+!ifdef URLUpdateInfo
+!ifndef BETA_UPDATE_CHANNEL
+ ${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0
+!endif
+!endif
+ ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0
+ ${WriteRegDWORD2} $1 "$0" "NoModify" 1 0
+ ${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0
+
+ ${GetSize} "$8" "/S=0K" $R2 $R3 $R4
+ ${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0
+
+ ${If} "$TmpVal" == "HKLM"
+ SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
+ ${Else}
+ SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define SetUninstallKeys "!insertmacro SetUninstallKeys"
+
+; Due to a bug when associating some file handlers, only SHCTX was checked for
+; some file types such as ".pdf". SHCTX is set to HKCU or HKLM depending on
+; whether the installer has write access to HKLM. The bug would happen when
+; HCKU was checked and didn't exist since programs aren't required to set the
+; HKCU Software\Classes keys when associating handlers. The fix uses the merged
+; view in HKCR to check for existance of an existing association. This macro
+; cleans affected installations by removing the HKLM and HKCU value if it is set
+; to FirefoxHTML when there is a value for PersistentHandler or by removing the
+; HKCU value when the HKLM value has a value other than an empty string.
+!macro FixBadFileAssociation FILE_TYPE
+ ; Only delete the default value in case the key has values for OpenWithList,
+ ; OpenWithProgids, PersistentHandler, etc.
+ ReadRegStr $0 HKCU "Software\Classes\${FILE_TYPE}" ""
+ ${WordFind} "$0" "-" "+1{" $0
+ ReadRegStr $1 HKLM "Software\Classes\${FILE_TYPE}" ""
+ ${WordFind} "$1" "-" "+1{" $1
+ ReadRegStr $2 HKCR "${FILE_TYPE}\PersistentHandler" ""
+ ${If} "$2" != ""
+ ; Since there is a persistent handler remove FirefoxHTML as the default
+ ; value from both HKCU and HKLM if it set to FirefoxHTML.
+ ${If} "$0" == "FirefoxHTML"
+ DeleteRegValue HKCU "Software\Classes\${FILE_TYPE}" ""
+ ${EndIf}
+ ${If} "$1" == "FirefoxHTML"
+ DeleteRegValue HKLM "Software\Classes\${FILE_TYPE}" ""
+ ${EndIf}
+ ${ElseIf} "$0" == "FirefoxHTML"
+ ; Since HKCU is set to FirefoxHTML remove FirefoxHTML as the default value
+ ; from HKCU if HKLM is set to a value other than an empty string.
+ ${If} "$1" != ""
+ DeleteRegValue HKCU "Software\Classes\${FILE_TYPE}" ""
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define FixBadFileAssociation "!insertmacro FixBadFileAssociation"
+
+; Add app specific handler registry entries under Software\Classes if they
+; don't exist (does not use SHCTX).
+!macro FixClassKeys
+ StrCpy $1 "SOFTWARE\Classes"
+
+ ; File handler keys and name value pairs that may need to be created during
+ ; install or upgrade.
+ ReadRegStr $0 HKCR ".shtml" "Content Type"
+ ${If} "$0" == ""
+ StrCpy $0 "$1\.shtml"
+ ${WriteRegStr2} $TmpVal "$1\.shtml" "" "shtmlfile" 0
+ ${WriteRegStr2} $TmpVal "$1\.shtml" "Content Type" "text/html" 0
+ ${WriteRegStr2} $TmpVal "$1\.shtml" "PerceivedType" "text" 0
+ ${EndIf}
+
+ ReadRegStr $0 HKCR ".xht" "Content Type"
+ ${If} "$0" == ""
+ ${WriteRegStr2} $TmpVal "$1\.xht" "" "xhtfile" 0
+ ${WriteRegStr2} $TmpVal "$1\.xht" "Content Type" "application/xhtml+xml" 0
+ ${EndIf}
+
+ ReadRegStr $0 HKCR ".xhtml" "Content Type"
+ ${If} "$0" == ""
+ ${WriteRegStr2} $TmpVal "$1\.xhtml" "" "xhtmlfile" 0
+ ${WriteRegStr2} $TmpVal "$1\.xhtml" "Content Type" "application/xhtml+xml" 0
+ ${EndIf}
+
+ ; Remove possibly badly associated file types
+ ${FixBadFileAssociation} ".pdf"
+ ${FixBadFileAssociation} ".oga"
+ ${FixBadFileAssociation} ".ogg"
+ ${FixBadFileAssociation} ".ogv"
+ ${FixBadFileAssociation} ".pdf"
+ ${FixBadFileAssociation} ".webm"
+!macroend
+!define FixClassKeys "!insertmacro FixClassKeys"
+
+; Updates protocol handlers if their registry open command value is for this
+; install location (uses SHCTX).
+!macro UpdateProtocolHandlers
+ ; Store the command to open the app with an url in a register for easy access.
+ ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
+ StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
+
+ ; Only set the file and protocol handlers if the existing one under HKCR is
+ ; for this install location.
+
+ ${IsHandlerForInstallDir} "FirefoxHTML-$AppUserModelID" $R9
+ ${If} "$R9" == "true"
+ ; An empty string is used for the 5th param because FirefoxHTML is not a
+ ; protocol handler.
+ ${AddDisabledDDEHandlerValues} "FirefoxHTML-$AppUserModelID" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} HTML Document" ""
+ ${Else}
+ ${IsHandlerForInstallDir} "FirefoxHTML" $R9
+ ${If} "$R9" == "true"
+ ${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} HTML Document" ""
+ ${EndIf}
+ ${EndIf}
+
+ ; FirefoxPDF-* was added after FirefoxHTML and FirefoxURL, so we've never
+ ; supported bare "FirefoxPDF". But we won't have it from the installer, so we
+ ; add/update it unconditionally. `PostUpdate` is gated on `uninstall.log`
+ ; being present, so the invocation here will only happen for installed
+ ; directories, not unpackaged directories.
+ ${AddDisabledDDEHandlerValues} "FirefoxPDF-$AppUserModelID" "$2" "$8,${IDI_DOCUMENT_PDF_ZERO_BASED}" \
+ "${AppRegName} PDF Document" ""
+
+ ${IsHandlerForInstallDir} "FirefoxURL-$AppUserModelID" $R9
+ ${If} "$R9" == "true"
+ ${AddDisabledDDEHandlerValues} "FirefoxURL-$AppUserModelID" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} URL" "true"
+ ${Else}
+ ${IsHandlerForInstallDir} "FirefoxURL" $R9
+ ${If} "$R9" == "true"
+ ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" \
+ "${AppRegName} URL" "true"
+ ${EndIf}
+ ${EndIf}
+
+ ; An empty string is used for the 4th & 5th params because the following
+ ; protocol handlers already have a display name and the additional keys
+ ; required for a protocol handler.
+
+ ${IsHandlerForInstallDir} "ftp" $R9
+ ${If} "$R9" == "true"
+ ; In the past, we supported ftp, so we need to delete any registration.
+ ${AddDisabledDDEHandlerValues} "ftp" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" "delete"
+ ${EndIf}
+
+ ${IsHandlerForInstallDir} "http" $R9
+ ${If} "$R9" == "true"
+ ${AddDisabledDDEHandlerValues} "http" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" ""
+ ${EndIf}
+
+ ${IsHandlerForInstallDir} "https" $R9
+ ${If} "$R9" == "true"
+ ${AddDisabledDDEHandlerValues} "https" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" ""
+ ${EndIf}
+
+ ${IsHandlerForInstallDir} "mailto" $R9
+ ${If} "$R9" == "true"
+ ${AddDisabledDDEHandlerValues} "mailto" "$2" "$8,${IDI_DOCUMENT_ZERO_BASED}" "" ""
+ ${EndIf}
+!macroend
+!define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers"
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+; Adds maintenance service certificate keys for the install dir.
+; For the cert to work, it must also be signed by a trusted cert for the user.
+!macro AddMaintCertKeys
+ Push $R0
+ ; Allow main Mozilla cert information for updates
+ ; This call will push the needed key on the stack
+ ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
+ Pop $R0
+ ${If} $R0 != ""
+ ; More than one certificate can be specified in a different subfolder
+ ; for example: $R0\1, but each individual binary can be signed
+ ; with at most one certificate. A fallback certificate can only be used
+ ; if the binary is replaced with a different certificate.
+ ; We always use the 64bit registry for certs.
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView 64
+ ${EndIf}
+
+ ; PrefetchProcessName was originally used to experiment with deleting
+ ; Windows prefetch as a speed optimization. It is no longer used though.
+ DeleteRegValue HKLM "$R0" "prefetchProcessName"
+
+ ; Setting the Attempted value will ensure that a new Maintenance Service
+ ; install will never be attempted again after this from updates. The value
+ ; is used only to see if updates should attempt new service installs.
+ WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
+
+ ; These values associate the allowed certificates for the current
+ ; installation.
+ WriteRegStr HKLM "$R0\0" "name" "${CERTIFICATE_NAME}"
+ WriteRegStr HKLM "$R0\0" "issuer" "${CERTIFICATE_ISSUER}"
+ ; These values associate the allowed certificates for the previous
+ ; installation, so that we can update from it cleanly using the
+ ; old updater.exe (which will still have this signature).
+ WriteRegStr HKLM "$R0\1" "name" "${CERTIFICATE_NAME_PREVIOUS}"
+ WriteRegStr HKLM "$R0\1" "issuer" "${CERTIFICATE_ISSUER_PREVIOUS}"
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView lastused
+ ${EndIf}
+ ClearErrors
+ ${EndIf}
+ ; Restore the previously used value back
+ Pop $R0
+!macroend
+!define AddMaintCertKeys "!insertmacro AddMaintCertKeys"
+!endif
+
+!macro RegisterAccessibleHandler
+ ${RegisterDLL} "$INSTDIR\AccessibleHandler.dll"
+!macroend
+!define RegisterAccessibleHandler "!insertmacro RegisterAccessibleHandler"
+
+!macro RegisterAccessibleMarshal
+ ${RegisterDLL} "$INSTDIR\AccessibleMarshal.dll"
+!macroend
+!define RegisterAccessibleMarshal "!insertmacro RegisterAccessibleMarshal"
+
+; Removes various registry entries for reasons noted below (does not use SHCTX).
+!macro RemoveDeprecatedKeys
+ StrCpy $0 "SOFTWARE\Classes"
+ ; Remove support for launching chrome urls from the shell during install or
+ ; update if the DefaultIcon is from firefox.exe (Bug 301073).
+ ${RegCleanAppHandler} "chrome"
+
+ ; Remove protocol handler registry keys added by the MS shim
+ DeleteRegKey HKLM "Software\Classes\Firefox.URL"
+ DeleteRegKey HKCU "Software\Classes\Firefox.URL"
+!macroend
+!define RemoveDeprecatedKeys "!insertmacro RemoveDeprecatedKeys"
+
+; Removes various directories and files for reasons noted below.
+!macro RemoveDeprecatedFiles
+ ; Remove the toplevel chrome.manifest added by bug 1295542.
+ ${If} ${FileExists} "$INSTDIR\chrome.manifest"
+ Delete "$INSTDIR\chrome.manifest"
+ ${EndIf}
+
+ ; Remove talkback if it is present (remove after bug 386760 is fixed)
+ ${If} ${FileExists} "$INSTDIR\extensions\talkback@mozilla.org"
+ RmDir /r /REBOOTOK "$INSTDIR\extensions\talkback@mozilla.org"
+ ${EndIf}
+
+ ; Remove the Java Console extension (bug 1165156)
+ ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0031-ABCDEFFEDCBA}"
+ RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0031-ABCDEFFEDCBA}"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0034-ABCDEFFEDCBA}"
+ RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0034-ABCDEFFEDCBA}"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0039-ABCDEFFEDCBA}"
+ RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0039-ABCDEFFEDCBA}"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0045-ABCDEFFEDCBA}"
+ RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0045-ABCDEFFEDCBA}"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0000-ABCDEFFEDCBA}"
+ RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0000-ABCDEFFEDCBA}"
+ ${EndIf}
+!macroend
+!define RemoveDeprecatedFiles "!insertmacro RemoveDeprecatedFiles"
+
+; Converts specific partner distribution.ini from ansi to utf-8 (bug 882989)
+!macro FixDistributionsINI
+ StrCpy $1 "$INSTDIR\distribution\distribution.ini"
+ StrCpy $2 "$INSTDIR\distribution\utf8fix"
+ StrCpy $0 "0" ; Default to not attempting to fix
+
+ ; Check if the distribution.ini settings are for a partner build that needs
+ ; to have its distribution.ini converted from ansi to utf-8.
+ ${If} ${FileExists} "$1"
+ ${Unless} ${FileExists} "$2"
+ ReadINIStr $3 "$1" "Preferences" "app.distributor"
+ ${If} "$3" == "yahoo"
+ ReadINIStr $3 "$1" "Preferences" "app.distributor.channel"
+ ${If} "$3" == "de"
+ ${OrIf} "$3" == "es"
+ ${OrIf} "$3" == "e1"
+ ${OrIf} "$3" == "mx"
+ StrCpy $0 "1"
+ ${EndIf}
+ ${EndIf}
+ ; Create the utf8fix so this only runs once
+ FileOpen $3 "$2" w
+ FileClose $3
+ ${EndUnless}
+ ${EndIf}
+
+ ${If} "$0" == "1"
+ StrCpy $0 "0"
+ ClearErrors
+ ReadINIStr $3 "$1" "Global" "version"
+ ${Unless} ${Errors}
+ StrCpy $4 "$3" 2
+ ${If} "$4" == "1."
+ StrCpy $4 "$3" "" 2 ; Everything after "1."
+ ${If} $4 < 23
+ StrCpy $0 "1"
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+ ${EndIf}
+
+ ${If} "$0" == "1"
+ ClearErrors
+ FileOpen $3 "$1" r
+ ${If} ${Errors}
+ FileClose $3
+ ${Else}
+ StrCpy $2 "$INSTDIR\distribution\distribution.new"
+ ClearErrors
+ FileOpen $4 "$2" w
+ ${If} ${Errors}
+ FileClose $3
+ FileClose $4
+ ${Else}
+ StrCpy $0 "0" ; Default to not replacing the original distribution.ini
+ ${Do}
+ FileReadByte $3 $5
+ ${If} $5 == ""
+ ${Break}
+ ${EndIf}
+ ${If} $5 == 233 ; ansi é
+ StrCpy $0 "1"
+ FileWriteByte $4 195
+ FileWriteByte $4 169
+ ${ElseIf} $5 == 241 ; ansi ñ
+ StrCpy $0 "1"
+ FileWriteByte $4 195
+ FileWriteByte $4 177
+ ${ElseIf} $5 == 252 ; ansi ü
+ StrCpy $0 "1"
+ FileWriteByte $4 195
+ FileWriteByte $4 188
+ ${ElseIf} $5 < 128
+ FileWriteByte $4 $5
+ ${EndIf}
+ ${Loop}
+ FileClose $3
+ FileClose $4
+ ${If} "$0" == "1"
+ ClearErrors
+ Rename "$1" "$1.bak"
+ ${Unless} ${Errors}
+ Rename "$2" "$1"
+ Delete "$1.bak"
+ ${EndUnless}
+ ${Else}
+ Delete "$2"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define FixDistributionsINI "!insertmacro FixDistributionsINI"
+
+; For updates, adds a pinned shortcut to Task Bar on update for Windows 7
+; and 8 if this macro has never been called before and the application
+; is default (see PinToTaskBar for more details). This doesn't get called
+; for Windows 10 and 11 on updates, so we will never pin on update there.
+;
+; For installs, adds a taskbar pin if SHOULD_PIN is 1. (Defaults to 1,
+; but is controllable through the UI, ini file, and command line flags.)
+!macro MigrateTaskBarShortcut SHOULD_PIN
+ ${GetShortcutsLogPath} $0
+ ${If} ${FileExists} "$0"
+ ClearErrors
+ ReadINIStr $1 "$0" "TASKBAR" "Migrated"
+ ${If} ${Errors}
+ ClearErrors
+ WriteIniStr "$0" "TASKBAR" "Migrated" "true"
+ WriteRegDWORD HKCU \
+ "Software\Mozilla\${AppName}\Installer\$AppUserModelID" \
+ "WasPinnedToTaskbar" 1
+ ${If} ${AtLeastWin7}
+ ${If} "${SHOULD_PIN}" == "1"
+ ${PinToTaskBar}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define MigrateTaskBarShortcut "!insertmacro MigrateTaskBarShortcut"
+
+; Adds a pinned Task Bar shortcut on Windows 7 if there isn't one for the main
+; application executable already. Existing pinned shortcuts for the same
+; application model ID must be removed first to prevent breaking the pinned
+; item's lists but multiple installations with the same application model ID is
+; an edgecase. If removing existing pinned shortcuts with the same application
+; model ID removes a pinned pinned Start Menu shortcut this will also add a
+; pinned Start Menu shortcut.
+!macro PinToTaskBar
+ ${If} ${AtLeastWin7}
+ StrCpy $8 "false" ; Whether a shortcut had to be created
+ ${IsPinnedToTaskBar} "$INSTDIR\${FileMainEXE}" $R9
+ ${If} "$R9" == "false"
+ ; Find an existing Start Menu shortcut or create one to use for pinning
+ ${GetShortcutsLogPath} $0
+ ${If} ${FileExists} "$0"
+ ClearErrors
+ ReadINIStr $1 "$0" "STARTMENU" "Shortcut0"
+ ${Unless} ${Errors}
+ SetShellVarContext all ; Set SHCTX to all users
+ ${Unless} ${FileExists} "$SMPROGRAMS\$1"
+ SetShellVarContext current ; Set SHCTX to the current user
+ ${Unless} ${FileExists} "$SMPROGRAMS\$1"
+ StrCpy $8 "true"
+ CreateShortCut "$SMPROGRAMS\$1" "$INSTDIR\${FileMainEXE}"
+ ${If} ${FileExists} "$SMPROGRAMS\$1"
+ ShellLink::SetShortCutWorkingDirectory "$SMPROGRAMS\$1" \
+ "$INSTDIR"
+ ${If} "$AppUserModelID" != ""
+ ApplicationID::Set "$SMPROGRAMS\$1" "$AppUserModelID" "true"
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+ ${EndUnless}
+
+ ${If} ${FileExists} "$SMPROGRAMS\$1"
+ ; Count of Start Menu pinned shortcuts before unpinning.
+ ${PinnedToStartMenuLnkCount} $R9
+
+ ; Having multiple shortcuts pointing to different installations with
+ ; the same AppUserModelID (e.g. side by side installations of the
+ ; same version) will make the TaskBar shortcut's lists into an bad
+ ; state where the lists are not shown. To prevent this first
+ ; uninstall the pinned item.
+ ApplicationID::UninstallPinnedItem "$SMPROGRAMS\$1"
+
+ ; Count of Start Menu pinned shortcuts after unpinning.
+ ${PinnedToStartMenuLnkCount} $R8
+
+ ; If there is a change in the number of Start Menu pinned shortcuts
+ ; assume that unpinning unpinned a side by side installation from
+ ; the Start Menu and pin this installation to the Start Menu.
+ ${Unless} $R8 == $R9
+ ; Pin the shortcut to the Start Menu. 5381 is the shell32.dll
+ ; resource id for the "Pin to Start Menu" string.
+ InvokeShellVerb::DoIt "$SMPROGRAMS" "$1" "5381"
+ ${EndUnless}
+
+ ${If} ${AtMostWin2012R2}
+ ; Pin the shortcut to the TaskBar. 5386 is the shell32.dll
+ ; resource id for the "Pin to Taskbar" string.
+ InvokeShellVerb::DoIt "$SMPROGRAMS" "$1" "5386"
+ ${ElseIf} ${AtMostWaaS} 1809
+ ; In Windows 10 the "Pin to Taskbar" resource was removed, so we
+ ; can't access the verb that way anymore. We have a create a
+ ; command key using the GUID that's assigned to this action and
+ ; then invoke that as a verb. This works up until build 1809
+ ReadRegStr $R9 HKLM \
+ "Software\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\Windows.taskbarpin" \
+ "ExplorerCommandHandler"
+ WriteRegStr HKCU "Software\Classes\*\shell\${AppRegName}-$AppUserModelID" "ExplorerCommandHandler" $R9
+ InvokeShellVerb::DoIt "$SMPROGRAMS" "$1" "${AppRegName}-$AppUserModelID"
+ DeleteRegKey HKCU "Software\Classes\*\shell\${AppRegName}-$AppUserModelID"
+ ${Else}
+ ; In the Windows 10 1903 and up (and Windows 11) the above no
+ ; longer works. We have yet another method for these versions
+ ; which is detailed in the PinToTaskbar plugin code.
+ PinToTaskbar::Pin "$SMPROGRAMS\$1"
+ ${EndIf}
+
+ ; Delete the shortcut if it was created
+ ${If} "$8" == "true"
+ Delete "$SMPROGRAMS\$1"
+ ${EndIf}
+ ${EndIf}
+
+ ${If} $TmpVal == "HKCU"
+ SetShellVarContext current ; Set SHCTX to the current user
+ ${Else}
+ SetShellVarContext all ; Set SHCTX to all users
+ ${EndIf}
+ ${EndUnless}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+!macroend
+!define PinToTaskBar "!insertmacro PinToTaskBar"
+
+; Removes the application's start menu directory along with its shortcuts if
+; they exist and if they exist creates a start menu shortcut in the root of the
+; start menu directory (bug 598779). If the application's start menu directory
+; is not empty after removing the shortucts the directory will not be removed
+; since these additional items were not created by the installer (uses SHCTX).
+!macro RemoveStartMenuDir
+ ${GetShortcutsLogPath} $0
+ ${If} ${FileExists} "$0"
+ ; Delete Start Menu Programs shortcuts, directory if it is empty, and
+ ; parent directories if they are empty up to but not including the start
+ ; menu directory.
+ ${GetLongPath} "$SMPROGRAMS" $1
+ ClearErrors
+ ReadINIStr $2 "$0" "SMPROGRAMS" "RelativePathToDir"
+ ${Unless} ${Errors}
+ ${GetLongPath} "$1\$2" $2
+ ${If} "$2" != ""
+ ; Delete shortucts in the Start Menu Programs directory.
+ StrCpy $3 0
+ ${Do}
+ ClearErrors
+ ReadINIStr $4 "$0" "SMPROGRAMS" "Shortcut$3"
+ ; Stop if there are no more entries
+ ${If} ${Errors}
+ ${ExitDo}
+ ${EndIf}
+ ${If} ${FileExists} "$2\$4"
+ ShellLink::GetShortCutTarget "$2\$4"
+ Pop $5
+ ${If} "$INSTDIR\${FileMainEXE}" == "$5"
+ Delete "$2\$4"
+ ${EndIf}
+ ${EndIf}
+ IntOp $3 $3 + 1 ; Increment the counter
+ ${Loop}
+ ; Delete Start Menu Programs directory and parent directories
+ ${Do}
+ ; Stop if the current directory is the start menu directory
+ ${If} "$1" == "$2"
+ ${ExitDo}
+ ${EndIf}
+ ClearErrors
+ RmDir "$2"
+ ; Stop if removing the directory failed
+ ${If} ${Errors}
+ ${ExitDo}
+ ${EndIf}
+ ${GetParent} "$2" $2
+ ${Loop}
+ ${EndIf}
+ DeleteINISec "$0" "SMPROGRAMS"
+ ${EndUnless}
+ ${EndIf}
+!macroend
+!define RemoveStartMenuDir "!insertmacro RemoveStartMenuDir"
+
+; Creates the shortcuts log ini file with the appropriate entries if it doesn't
+; already exist.
+!macro CreateShortcutsLog
+ ${GetShortcutsLogPath} $0
+ ${Unless} ${FileExists} "$0"
+ ${LogStartMenuShortcut} "${BrandShortName}.lnk"
+ ${LogQuickLaunchShortcut} "${BrandShortName}.lnk"
+ ${LogDesktopShortcut} "${BrandShortName}.lnk"
+ ${EndUnless}
+!macroend
+!define CreateShortcutsLog "!insertmacro CreateShortcutsLog"
+
+; The files to check if they are in use during (un)install so the restart is
+; required message is displayed. All files must be located in the $INSTDIR
+; directory.
+!macro PushFilesToCheck
+ ; The first string to be pushed onto the stack MUST be "end" to indicate
+ ; that there are no more files to check in $INSTDIR and the last string
+ ; should be ${FileMainEXE} so if it is in use the CheckForFilesInUse macro
+ ; returns after the first check.
+ Push "end"
+ Push "AccessibleHandler.dll"
+ Push "AccessibleMarshal.dll"
+ Push "IA2Marshal.dll"
+ Push "freebl3.dll"
+ Push "nssckbi.dll"
+ Push "nspr4.dll"
+ Push "nssdbm3.dll"
+ Push "mozsqlite3.dll"
+ Push "xpcom.dll"
+ Push "crashreporter.exe"
+ Push "default-browser-agent.exe"
+ Push "minidump-analyzer.exe"
+ Push "pingsender.exe"
+ Push "updater.exe"
+ Push "mozwer.dll"
+ Push "${FileMainEXE}"
+!macroend
+!define PushFilesToCheck "!insertmacro PushFilesToCheck"
+
+
+; Pushes the string "true" to the top of the stack if the Firewall service is
+; running and pushes the string "false" to the top of the stack if it isn't.
+!define SC_MANAGER_ALL_ACCESS 0x3F
+!define SERVICE_QUERY_CONFIG 0x0001
+!define SERVICE_QUERY_STATUS 0x0004
+!define SERVICE_RUNNING 0x4
+
+!macro IsFirewallSvcRunning
+ Push $R9
+ Push $R8
+ Push $R7
+ Push $R6
+ Push "false"
+
+ System::Call 'advapi32::OpenSCManagerW(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.R6'
+ ${If} $R6 != 0
+ ; MpsSvc is the Firewall service.
+ ; When opening the service with SERVICE_QUERY_CONFIG the return value will
+ ; be 0 if the service is not installed.
+ System::Call 'advapi32::OpenServiceW(i R6, t "MpsSvc", i ${SERVICE_QUERY_CONFIG}) i.R7'
+ ${If} $R7 != 0
+ System::Call 'advapi32::CloseServiceHandle(i R7) n'
+ ; Open the service with SERVICE_QUERY_STATUS so its status can be queried.
+ System::Call 'advapi32::OpenServiceW(i R6, t "MpsSvc", i ${SERVICE_QUERY_STATUS}) i.R7'
+ ${EndIf}
+ ; Did the calls to OpenServiceW succeed?
+ ${If} $R7 != 0
+ System::Call '*(i,i,i,i,i,i,i) i.R9'
+ ; Query the current status of the service.
+ System::Call 'advapi32::QueryServiceStatus(i R7, i $R9) i'
+ System::Call '*$R9(i, i.R8)'
+ System::Free $R9
+ System::Call 'advapi32::CloseServiceHandle(i R7) n'
+ IntFmt $R8 "0x%X" $R8
+ ${If} $R8 == ${SERVICE_RUNNING}
+ Pop $R9
+ Push "true"
+ ${EndIf}
+ ${EndIf}
+ System::Call 'advapi32::CloseServiceHandle(i R6) n'
+ ${EndIf}
+
+ Exch 1
+ Pop $R6
+ Exch 1
+ Pop $R7
+ Exch 1
+ Pop $R8
+ Exch 1
+ Pop $R9
+!macroend
+!define IsFirewallSvcRunning "!insertmacro IsFirewallSvcRunning"
+!define un.IsFirewallSvcRunning "!insertmacro IsFirewallSvcRunning"
+
+; Sets this installation as the default browser by setting the registry keys
+; under HKEY_CURRENT_USER via registry calls and using the AppAssocReg NSIS
+; plugin. This is a function instead of a macro so it is
+; easily called from an elevated instance of the binary. Since this can be
+; called by an elevated instance logging is not performed in this function.
+Function SetAsDefaultAppUserHKCU
+ ; See if we're using path hash suffixed registry keys for this install
+ ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
+ ClearErrors
+ ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+ ${If} ${Errors}
+ ${OrIf} ${AtMostWin2008R2}
+ ClearErrors
+ ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+ ${EndIf}
+ StrCpy $0 $0 -2
+ ${If} $0 != $8
+ ${If} $AppUserModelID == ""
+ ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
+ ${EndIf}
+ StrCpy $R9 "${AppRegName}-$AppUserModelID"
+ ${EndIf}
+
+ ; Set ourselves as the user's selected StartMenuInternet browser, but only
+ ; if we have StartMenuInternet registry keys that are for this install.
+ ClearErrors
+ ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+ ${If} ${Errors}
+ ${OrIf} ${AtMostWin2008R2}
+ ClearErrors
+ ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+ ${EndIf}
+ ${Unless} ${Errors}
+ ${GetPathFromString} "$0" $0
+ ${GetParent} "$0" $0
+ ${If} ${FileExists} "$0"
+ ${GetLongPath} "$0" $0
+ ${If} "$0" == "$INSTDIR"
+ ; On Windows >= 8, this function cannot do anything to actually set
+ ; the default browser, it can only set up the registry entries to
+ ; allow the user to do so. Getting here means that those entries already
+ ; exist for this installation, we just found them, so there is nothing
+ ; more to be done.
+ ${If} ${AtLeastWin8}
+ Return
+ ${Else}
+ WriteRegStr HKCU "Software\Clients\StartMenuInternet" "" "$R9"
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+
+ SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
+
+ ; It's unlikely that we didn't find a StartMenuInternet key above, but it is
+ ; possible; it likely would mean this copy of the application was extracted
+ ; directly from a ZIP file and the installer was never run.
+ ${If} ${AtLeastWin8}
+ ${SetStartMenuInternet} "HKCU"
+ ${FixShellIconHandler} "HKCU"
+ ${FixClassKeys} ; Does not use SHCTX
+ ${EndIf}
+
+ ${SetHandlers}
+
+ ; Only register as the handler if the app registry name
+ ; exists under the RegisteredApplications registry key. The protocol and
+ ; file handlers set previously at the user level will associate this install
+ ; as the default browser.
+ ClearErrors
+ ReadRegStr $0 HKLM "Software\RegisteredApplications" "$R9"
+ ${Unless} ${Errors}
+ ; This is all protected by a user choice hash in Windows 8 so it won't
+ ; help, but it also won't hurt.
+ AppAssocReg::SetAppAsDefault "$R9" ".htm" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" ".html" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" ".shtml" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" ".webp" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" ".avif" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" ".xht" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" ".xhtml" "file"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" "http" "protocol"
+ Pop $0
+ AppAssocReg::SetAppAsDefault "$R9" "https" "protocol"
+ Pop $0
+ ${EndUnless}
+ ${RemoveDeprecatedKeys}
+ ${MigrateTaskBarShortcut} "$R0"
+FunctionEnd
+
+; Helper for updating the shortcut application model IDs.
+Function FixShortcutAppModelIDs
+ ${If} ${AtLeastWin7}
+ ${AndIf} "$AppUserModelID" != ""
+ ${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "$AppUserModelID" $0
+ ${EndIf}
+FunctionEnd
+
+; Helper for adding Firewall exceptions during install and after app update.
+Function AddFirewallEntries
+ ${IsFirewallSvcRunning}
+ Pop $0
+ ${If} "$0" == "true"
+ liteFirewallW::AddRule "$INSTDIR\${FileMainEXE}" "${BrandShortName} ($INSTDIR)"
+ ${EndIf}
+FunctionEnd
+
+; The !ifdef NO_LOG prevents warnings when compiling the installer.nsi due to
+; this function only being used by the uninstaller.nsi.
+!ifdef NO_LOG
+
+Function SetAsDefaultAppUser
+ ; AddTaskbarSC is needed by MigrateTaskBarShortcut, which is called by
+ ; SetAsDefaultAppUserHKCU. If this is called via ExecCodeSegment,
+ ; MigrateTaskBarShortcut will not see the value of AddTaskbarSC, so we
+ ; send it via a register instead.
+ StrCpy $R0 $AddTaskbarSC
+ ; On Win8, we want to avoid having a UAC prompt since we'll already have
+ ; another action for control panel default browser selection popping up
+ ; to the user. Win8 is the first OS where the start menu keys can be
+ ; added into HKCU. The call to SetAsDefaultAppUserHKCU will have already
+ ; set the HKCU keys for SetStartMenuInternet.
+ ${If} ${AtLeastWin8}
+ ; Check if this is running in an elevated process
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $0
+ ${If} ${Errors} ; Not elevated
+ Call SetAsDefaultAppUserHKCU
+ ${Else} ; Elevated - execute the function in the unelevated process
+ GetFunctionAddress $0 SetAsDefaultAppUserHKCU
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+ Return ; Nothing more needs to be done
+ ${EndIf}
+
+ ; Before Win8, it is only possible to set this installation of the application
+ ; as the StartMenuInternet handler if it was added to the HKLM
+ ; StartMenuInternet registry keys.
+ ; http://support.microsoft.com/kb/297878
+
+ ; Check if this install location registered as a StartMenuInternet client
+ ClearErrors
+ ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\DefaultIcon" ""
+ ${If} ${Errors}
+ ${OrIf} ${AtMostWin2008R2}
+ ClearErrors
+ ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\DefaultIcon" ""
+ ${EndIf}
+ ${If} ${Errors}
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
+ ClearErrors
+ ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+ ${If} ${Errors}
+ ${OrIf} ${AtMostWin2008R2}
+ ClearErrors
+ ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+ ${EndIf}
+ ${EndIf}
+
+ ${Unless} ${Errors}
+ ${GetPathFromString} "$0" $0
+ ${GetParent} "$0" $0
+ ${If} ${FileExists} "$0"
+ ${GetLongPath} "$0" $0
+ ${If} "$0" == "$INSTDIR"
+ ; Check if this is running in an elevated process
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $0
+ ${If} ${Errors} ; Not elevated
+ Call SetAsDefaultAppUserHKCU
+ ${Else} ; Elevated - execute the function in the unelevated process
+ GetFunctionAddress $0 SetAsDefaultAppUserHKCU
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+ Return ; Nothing more needs to be done
+ ${EndIf}
+ ${EndIf}
+ ${EndUnless}
+
+ ; The code after ElevateUAC won't be executed when the user:
+ ; a) is a member of the administrators group (e.g. elevation is required)
+ ; b) is not a member of the administrators group and chooses to elevate
+ ${ElevateUAC}
+
+ ${SetStartMenuInternet} "HKLM"
+
+ SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
+
+ ${FixClassKeys} ; Does not use SHCTX
+ ${FixShellIconHandler} "HKLM"
+ ${RemoveDeprecatedKeys} ; Does not use SHCTX
+
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $0
+ ${If} ${Errors}
+ Call SetAsDefaultAppUserHKCU
+ ${Else}
+ GetFunctionAddress $0 SetAsDefaultAppUserHKCU
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+FunctionEnd
+!define SetAsDefaultAppUser "Call SetAsDefaultAppUser"
+
+!endif ; NO_LOG
+
+!ifdef MOZ_LAUNCHER_PROCESS
+!macro ResetLauncherProcessDefaults
+ # By deleting these values, we remove remnants of any force-disable settings
+ # that may have been set during the SHIELD study in 67. Note that this setting
+ # was only intended to distinguish between test and control groups for the
+ # purposes of the study, not as a user preference.
+ DeleteRegValue HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Launcher"
+ DeleteRegValue HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Browser"
+!macroend
+!define ResetLauncherProcessDefaults "!insertmacro ResetLauncherProcessDefaults"
+!endif
+
+!macro WriteToastNotificationRegistration RegKey
+ ; Find or create a GUID to use for this installation. For simplicity, We
+ ; always update our registration.
+ ClearErrors
+ ReadRegStr $0 SHCTX "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "CustomActivator"
+ ${If} "$0" == ""
+ ; Create a GUID.
+ System::Call "rpcrt4::UuidCreate(g . r0)i"
+ ; StringFromGUID2 (which is what System::Call uses internally to stringify
+ ; GUIDs) includes braces in its output. In this case, we want the braces.
+ ${EndIf}
+
+ ; Check if this is an ESR release.
+ ClearErrors
+ ${WordFind} "${UpdateChannel}" "esr" "E#" $1
+ ${If} ${Errors}
+ StrCpy $1 ""
+ ${Else}
+ StrCpy $1 " ESR"
+ ${EndIf}
+
+ ; Write the following keys and values to the registry.
+ ; HKEY_CURRENT_USER\Software\Classes\AppID\{GUID} DllSurrogate : REG_SZ = ""
+ ; \AppUserModelId\{ToastAumidPrefix}{install hash} CustomActivator : REG_SZ = {GUID}
+ ; DisplayName : REG_EXPAND_SZ = {display name}
+ ; IconUri : REG_EXPAND_SZ = {icon path}
+ ; \CLSID\{GUID} AppID : REG_SZ = {GUID}
+ ; \InprocServer32 (Default) : REG_SZ = {notificationserver.dll path}
+ ${WriteRegStr2} ${RegKey} "Software\Classes\AppID\$0" "DllSurrogate" "" 0
+ ${WriteRegStr2} ${RegKey} "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "CustomActivator" "$0" 0
+ ${WriteRegStr2} ${RegKey} "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "DisplayName" "${BrandFullNameInternal}$1" 0
+ ; Sadly, we can't use embedded resources like `firefox.exe,1`.
+ ${WriteRegStr2} ${RegKey} "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "IconUri" "$INSTDIR\browser\VisualElements\VisualElements_70.png" 0
+ ${WriteRegStr2} ${RegKey} "Software\Classes\CLSID\$0" "AppID" "$0" 0
+ ${WriteRegStr2} ${RegKey} "Software\Classes\CLSID\$0\InProcServer32" "" "$INSTDIR\notificationserver.dll" 0
+!macroend
+!define WriteToastNotificationRegistration "!insertmacro WriteToastNotificationRegistration"
diff --git a/browser/installer/windows/nsis/stub.nsi b/browser/installer/windows/nsis/stub.nsi
new file mode 100644
index 0000000000..3384198e96
--- /dev/null
+++ b/browser/installer/windows/nsis/stub.nsi
@@ -0,0 +1,1772 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Required Plugins:
+# AppAssocReg
+# CertCheck
+# InetBgDL
+# ShellLink
+# UAC
+
+; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
+!verbose 3
+
+SetDatablockOptimize on
+SetCompress off
+CRCCheck on
+
+RequestExecutionLevel user
+
+Unicode true
+ManifestSupportedOS all
+ManifestDPIAware true
+
+!addplugindir ./
+
+Var CheckboxSetAsDefault
+Var CheckboxShortcuts
+Var CheckboxSendPing
+Var CheckboxInstallMaintSvc
+Var CheckboxCleanupProfile
+
+Var FontFamilyName
+
+Var CanWriteToInstallDir
+Var HasRequiredSpaceAvailable
+Var IsDownloadFinished
+Var DownloadSizeBytes
+Var DownloadReset
+Var ExistingTopDir
+Var SpaceAvailableBytes
+Var InitialInstallDir
+Var HandleDownload
+Var CanSetAsDefault
+Var InstallCounterStep
+Var InstallTotalSteps
+Var ProgressCompleted
+Var UsingHighContrastMode
+
+Var ExitCode
+Var FirefoxLaunchCode
+
+Var StartDownloadPhaseTickCount
+; Since the Intro and Options pages can be displayed multiple times the total
+; seconds spent on each of these pages is reported.
+Var IntroPhaseSeconds
+Var OptionsPhaseSeconds
+; The tick count for the last download.
+Var StartLastDownloadTickCount
+; The number of seconds from the start of the download phase until the first
+; bytes are received. This is only recorded for first request so it is possible
+; to determine connection issues for the first request.
+Var DownloadFirstTransferSeconds
+; The last four tick counts are for the end of a phase in the installation page.
+Var EndDownloadPhaseTickCount
+Var EndPreInstallPhaseTickCount
+Var EndInstallPhaseTickCount
+Var EndFinishPhaseTickCount
+
+Var InitialInstallRequirementsCode
+Var ExistingProfile
+Var ExistingVersion
+Var ExistingBuildID
+Var DownloadedBytes
+Var DownloadRetryCount
+Var OpenedDownloadPage
+Var DownloadServerIP
+Var PostSigningData
+Var PreviousInstallDir
+Var ProfileCleanupPromptType
+Var AppLaunchWaitTickCount
+Var TimerHandle
+
+!define ARCH_X86 1
+!define ARCH_AMD64 2
+!define ARCH_AARCH64 3
+Var ArchToInstall
+
+; Uncomment the following to prevent pinging the metrics server when testing
+; the stub installer
+;!define STUB_DEBUG
+
+!define StubURLVersion "v8"
+
+; Successful install exit code
+!define ERR_SUCCESS 0
+
+/**
+ * The following errors prefixed with ERR_DOWNLOAD apply to the download phase.
+ */
+; The download was cancelled by the user
+!define ERR_DOWNLOAD_CANCEL 10
+
+; Too many attempts to download. The maximum attempts is defined in
+; DownloadMaxRetries.
+!define ERR_DOWNLOAD_TOO_MANY_RETRIES 11
+
+/**
+ * The following errors prefixed with ERR_PREINSTALL apply to the pre-install
+ * check phase.
+ */
+; Unable to acquire a file handle to the downloaded file
+!define ERR_PREINSTALL_INVALID_HANDLE 20
+
+; The downloaded file's certificate is not trusted by the certificate store.
+!define ERR_PREINSTALL_CERT_UNTRUSTED 21
+
+; The downloaded file's certificate attribute values were incorrect.
+!define ERR_PREINSTALL_CERT_ATTRIBUTES 22
+
+; The downloaded file's certificate is not trusted by the certificate store and
+; certificate attribute values were incorrect.
+!define ERR_PREINSTALL_CERT_UNTRUSTED_AND_ATTRIBUTES 23
+
+; Timed out while waiting for the certificate checks to run.
+!define ERR_PREINSTALL_CERT_TIMEOUT 24
+
+/**
+ * The following errors prefixed with ERR_INSTALL apply to the install phase.
+ */
+; The installation timed out. The installation timeout is defined by the number
+; of progress steps defined in InstallTotalSteps and the install timer
+; interval defined in InstallIntervalMS
+!define ERR_INSTALL_TIMEOUT 30
+
+; Maximum times to retry the download before displaying an error
+!define DownloadMaxRetries 9
+
+; Interval before retrying to download. 3 seconds is used along with 10
+; attempted downloads (the first attempt along with 9 retries) to give a
+; minimum of 30 seconds or retrying before giving up.
+!define DownloadRetryIntervalMS 3000
+
+; Interval for the download timer
+!define DownloadIntervalMS 200
+
+; Timeout for the certificate check
+!define PreinstallCertCheckMaxWaitSec 30
+
+; Interval for the install timer
+!define InstallIntervalMS 100
+
+; Number of steps for the install progress.
+; This might not be enough when installing on a slow network drive so it will
+; fallback to downloading the full installer if it reaches this number.
+
+; Approximately 200 seconds with a 100 millisecond timer.
+!define InstallCleanTotalSteps 2000
+
+; Approximately 215 seconds with a 100 millisecond timer.
+!define InstallPaveOverTotalSteps 2150
+
+; Blurb duty cycle
+!define BlurbDisplayMS 19500
+!define BlurbBlankMS 500
+
+; Interval between checks for the application window and progress bar updates.
+!define AppLaunchWaitIntervalMS 100
+
+; Total time to wait for the application to start before just exiting.
+!define AppLaunchWaitTimeoutMS 10000
+
+; Maximum value of the download/install/launch progress bar, and the end values
+; for each individual stage.
+!define PROGRESS_BAR_TOTAL_STEPS 500
+!define PROGRESS_BAR_DOWNLOAD_END_STEP 300
+!define PROGRESS_BAR_INSTALL_END_STEP 475
+!define PROGRESS_BAR_APP_LAUNCH_END_STEP 500
+
+; Amount of physical memory required for the 64-bit build to be selected (2 GB).
+; Machines with this or less RAM get the 32-bit build, even with a 64-bit OS.
+!define RAM_NEEDED_FOR_64BIT 0x80000000
+
+; Attempt to elevate Standard Users in addition to users that
+; are a member of the Administrators group.
+!define NONADMIN_ELEVATE
+
+!define CONFIG_INI "config.ini"
+!define PARTNER_INI "$EXEDIR\partner.ini"
+
+!ifndef FILE_SHARE_READ
+ !define FILE_SHARE_READ 1
+!endif
+!ifndef GENERIC_READ
+ !define GENERIC_READ 0x80000000
+!endif
+!ifndef OPEN_EXISTING
+ !define OPEN_EXISTING 3
+!endif
+!ifndef INVALID_HANDLE_VALUE
+ !define INVALID_HANDLE_VALUE -1
+!endif
+
+!define DefaultInstDir32bit "$PROGRAMFILES32\${BrandFullName}"
+!define DefaultInstDir64bit "$PROGRAMFILES64\${BrandFullName}"
+
+!include "LogicLib.nsh"
+!include "FileFunc.nsh"
+!include "TextFunc.nsh"
+!include "WinVer.nsh"
+!include "WordFunc.nsh"
+
+!insertmacro GetParameters
+!insertmacro GetOptions
+!insertmacro LineFind
+!insertmacro StrFilter
+
+!include "locales.nsi"
+!include "branding.nsi"
+
+!include "defines.nsi"
+
+; Must be included after defines.nsi
+!include "locale-fonts.nsh"
+
+; The OFFICIAL define is a workaround to support different urls for Release and
+; Beta since they share the same branding when building with other branches that
+; set the update channel to beta.
+!ifdef OFFICIAL
+!ifdef BETA_UPDATE_CHANNEL
+!undef URLStubDownloadX86
+!undef URLStubDownloadAMD64
+!undef URLStubDownloadAArch64
+!define URLStubDownloadX86 "https://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-beta-latest"
+!define URLStubDownloadAMD64 "https://download.mozilla.org/?os=win64&lang=${AB_CD}&product=firefox-beta-latest"
+!define URLStubDownloadAArch64 "https://download.mozilla.org/?os=win64-aarch64&lang=${AB_CD}&product=firefox-beta-latest"
+!undef URLManualDownload
+!define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=beta&installer_lang=${AB_CD}"
+!undef Channel
+!define Channel "beta"
+!endif
+!endif
+
+!include "common.nsh"
+
+!insertmacro CopyPostSigningData
+!insertmacro ElevateUAC
+!insertmacro GetLongPath
+!insertmacro GetPathFromString
+!insertmacro GetParent
+!insertmacro GetSingleInstallPath
+!insertmacro InitHashAppModelId
+!insertmacro IsUserAdmin
+!insertmacro RemovePrecompleteEntries
+!insertmacro SetBrandNameVars
+!insertmacro ITBL3Create
+!insertmacro UnloadUAC
+
+VIAddVersionKey "FileDescription" "${BrandShortName} Installer"
+VIAddVersionKey "OriginalFilename" "setup-stub.exe"
+
+Name "$BrandFullName"
+OutFile "setup-stub.exe"
+Icon "firefox64.ico"
+XPStyle on
+BrandingText " "
+ChangeUI IDD_INST "nsisui.exe"
+
+!ifdef ${AB_CD}_rtl
+ LoadLanguageFile "locale-rtl.nlf"
+!else
+ LoadLanguageFile "locale.nlf"
+!endif
+
+!include "nsisstrings.nlf"
+
+Caption "$(INSTALLER_WIN_CAPTION)"
+
+Page custom createProfileCleanup
+Page custom createInstall ; Download / Installation page
+
+Function .onInit
+ ; Remove the current exe directory from the search order.
+ ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
+ System::Call 'kernel32::SetDllDirectoryW(w "")'
+
+ StrCpy $LANGUAGE 0
+ ; This macro is used to set the brand name variables but the ini file method
+ ; isn't supported for the stub installer.
+ ${SetBrandNameVars} "$PLUGINSDIR\ignored.ini"
+
+ ; 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"
+
+ ; Windows NT 6.0 (Vista/Server 2008) and lower are not supported.
+ ${Unless} ${AtLeastWin7}
+ ${If} "$R7" == "0"
+ strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_CPU_MSG)"
+ ${Else}
+ strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_MSG)"
+ ${EndIf}
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$R7" IDCANCEL +2
+ ExecShell "open" "${URLSystemRequirements}"
+ Quit
+ ${EndUnless}
+
+ ; SSE2 CPU support
+ ${If} "$R7" == "0"
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_CPU_MSG)" IDCANCEL +2
+ ExecShell "open" "${URLSystemRequirements}"
+ Quit
+ ${EndIf}
+
+ Call GetArchToInstall
+ ${If} $ArchToInstall == ${ARCH_AARCH64}
+ ${OrIf} $ArchToInstall == ${ARCH_AMD64}
+ StrCpy $INSTDIR "${DefaultInstDir64bit}"
+ ${Else}
+ StrCpy $INSTDIR "${DefaultInstDir32bit}"
+ ${EndIf}
+
+ ; Require elevation if the user can elevate
+ ${ElevateUAC}
+
+ ; If we have any existing installation, use its location as the default
+ ; path for this install, even if it's not the same architecture.
+ SetRegView 32
+ SetShellVarContext all ; Set SHCTX to HKLM
+ ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
+
+ ${If} "$R9" == "false"
+ ${If} ${IsNativeAMD64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView 64
+ ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
+ ${EndIf}
+ ${EndIf}
+
+ ${If} "$R9" == "false"
+ SetShellVarContext current ; Set SHCTX to HKCU
+ ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
+ ${EndIf}
+
+ StrCpy $PreviousInstallDir ""
+ ${If} "$R9" != "false"
+ StrCpy $PreviousInstallDir "$R9"
+ StrCpy $INSTDIR "$PreviousInstallDir"
+ ${EndIf}
+
+ ; Used to determine if the default installation directory was used.
+ StrCpy $InitialInstallDir "$INSTDIR"
+
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" \
+ "Write Test"
+
+ ; Only display set as default when there is write access to HKLM and on Win7
+ ; and below.
+ ${If} ${Errors}
+ ${OrIf} ${AtLeastWin8}
+ StrCpy $CanSetAsDefault "false"
+ ${Else}
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ StrCpy $CanSetAsDefault "true"
+ ${EndIf}
+ StrCpy $CheckboxSetAsDefault "0"
+
+ ; Initialize the majority of variables except those that need to be reset
+ ; when a page is displayed.
+ StrCpy $ExitCode "${ERR_DOWNLOAD_CANCEL}"
+ StrCpy $IntroPhaseSeconds "0"
+ StrCpy $OptionsPhaseSeconds "0"
+ StrCpy $EndPreInstallPhaseTickCount "0"
+ StrCpy $EndInstallPhaseTickCount "0"
+ StrCpy $StartDownloadPhaseTickCount "0"
+ StrCpy $EndDownloadPhaseTickCount "0"
+ StrCpy $InitialInstallRequirementsCode ""
+ StrCpy $IsDownloadFinished ""
+ StrCpy $FirefoxLaunchCode "0"
+ StrCpy $CheckboxShortcuts "1"
+ StrCpy $CheckboxSendPing "1"
+ StrCpy $CheckboxCleanupProfile "0"
+ StrCpy $ProgressCompleted "0"
+!ifdef MOZ_MAINTENANCE_SERVICE
+ ; We can only install the maintenance service if the user is an admin.
+ Call IsUserAdmin
+ Pop $0
+ ${If} "$0" == "true"
+ StrCpy $CheckboxInstallMaintSvc "1"
+ ${Else}
+ StrCpy $CheckboxInstallMaintSvc "0"
+ ${EndIf}
+!else
+ StrCpy $CheckboxInstallMaintSvc "0"
+!endif
+
+ StrCpy $FontFamilyName ""
+!ifdef FONT_FILE1
+ ${If} ${FileExists} "$FONTS\${FONT_FILE1}"
+ StrCpy $FontFamilyName "${FONT_NAME1}"
+ ${EndIf}
+!endif
+
+!ifdef FONT_FILE2
+ ${If} $FontFamilyName == ""
+ ${AndIf} ${FileExists} "$FONTS\${FONT_FILE2}"
+ StrCpy $FontFamilyName "${FONT_NAME2}"
+ ${EndIf}
+!endif
+
+ ${If} $FontFamilyName == ""
+ StrCpy $FontFamilyName "$(^Font)"
+ ${EndIf}
+
+ InitPluginsDir
+ File /oname=$PLUGINSDIR\bgstub.jpg "bgstub.jpg"
+
+ ; Detect whether the machine is running with a high contrast theme.
+ ; We'll hide our background images in that case, both because they don't
+ ; always render properly and also to improve the contrast.
+ System::Call '*(i 12, i 0, p 0) p . r0'
+ ; 0x42 == SPI_GETHIGHCONTRAST
+ System::Call 'user32::SystemParametersInfoW(i 0x42, i 0, p r0, i 0)'
+ System::Call '*$0(i, i . r1, p)'
+ System::Free $0
+ IntOp $UsingHighContrastMode $1 & 1
+
+ SetShellVarContext all ; Set SHCTX to All Users
+ ; If the user doesn't have write access to the installation directory set
+ ; the installation directory to a subdirectory of the user's local
+ ; application directory (e.g. non-roaming).
+ Call CanWrite
+ ${If} "$CanWriteToInstallDir" == "false"
+ ${GetLocalAppDataFolder} $0
+ StrCpy $INSTDIR "$0\${BrandFullName}\"
+ Call CanWrite
+ ${EndIf}
+
+ Call CheckSpace
+
+ ${If} ${FileExists} "$INSTDIR"
+ ; Always display the long path if the path exists.
+ ${GetLongPath} "$INSTDIR" $INSTDIR
+ ${EndIf}
+
+ ; Check whether the install requirements are satisfied using the default
+ ; values for metrics.
+ ${If} "$InitialInstallRequirementsCode" == ""
+ ${If} "$CanWriteToInstallDir" != "true"
+ ${AndIf} "$HasRequiredSpaceAvailable" != "true"
+ StrCpy $InitialInstallRequirementsCode "1"
+ ${ElseIf} "$CanWriteToInstallDir" != "true"
+ StrCpy $InitialInstallRequirementsCode "2"
+ ${ElseIf} "$HasRequiredSpaceAvailable" != "true"
+ StrCpy $InitialInstallRequirementsCode "3"
+ ${Else}
+ StrCpy $InitialInstallRequirementsCode "0"
+ ${EndIf}
+ ${EndIf}
+
+ Call CanWrite
+ ${If} "$CanWriteToInstallDir" == "false"
+ MessageBox MB_OK|MB_ICONEXCLAMATION "$(WARN_WRITE_ACCESS_QUIT)$\n$\n$INSTDIR"
+ Quit
+ ${EndIf}
+
+ Call CheckSpace
+ ${If} "$HasRequiredSpaceAvailable" == "false"
+ MessageBox MB_OK|MB_ICONEXCLAMATION "$(WARN_DISK_SPACE_QUIT)"
+ Quit
+ ${EndIf}
+
+ ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
+
+ File /oname=$PLUGINSDIR\stub_common.css "stub_common.css"
+ File /oname=$PLUGINSDIR\stub_common.js "stub_common.js"
+FunctionEnd
+
+; .onGUIInit isn't needed except for RTL locales
+!ifdef ${AB_CD}_rtl
+Function .onGUIInit
+ ${MakeWindowRTL} $HWNDPARENT
+FunctionEnd
+!endif
+
+Function .onGUIEnd
+ Delete "$PLUGINSDIR\_temp"
+ Delete "$PLUGINSDIR\download.exe"
+ Delete "$PLUGINSDIR\${CONFIG_INI}"
+
+ ${UnloadUAC}
+FunctionEnd
+
+Function .onUserAbort
+ WebBrowser::CancelTimer $TimerHandle
+
+ ${If} "$IsDownloadFinished" != ""
+ ; Go ahead and cancel the download so it doesn't keep running while this
+ ; prompt is up. We'll resume it if the user decides to continue.
+ InetBgDL::Get /RESET /END
+
+ ${ShowTaskDialog} $(STUB_CANCEL_PROMPT_HEADING) \
+ $(STUB_CANCEL_PROMPT_MESSAGE) \
+ $(STUB_CANCEL_PROMPT_BUTTON_CONTINUE) \
+ $(STUB_CANCEL_PROMPT_BUTTON_EXIT)
+ Pop $0
+ ${If} $0 == 1002
+ ; The cancel button was clicked
+ Call LaunchHelpPage
+ Call SendPing
+ ${Else}
+ ; Either the continue button was clicked or the dialog was dismissed
+ Call StartDownload
+ ${EndIf}
+ ${Else}
+ Call SendPing
+ ${EndIf}
+
+ ; Aborting the abort will allow SendPing to hide the installer window and
+ ; close the installer after it sends the metrics ping, or allow us to just go
+ ; back to installing if that's what the user selected.
+ Abort
+FunctionEnd
+
+!macro _RegisterAllCustomFunctions
+ GetFunctionAddress $0 getUIString
+ WebBrowser::RegisterCustomFunction $0 "getUIString"
+
+ GetFunctionAddress $0 getTextDirection
+ WebBrowser::RegisterCustomFunction $0 "getTextDirection"
+
+ GetFunctionAddress $0 getFontName
+ WebBrowser::RegisterCustomFunction $0 "getFontName"
+
+ GetFunctionAddress $0 getIsHighContrast
+ WebBrowser::RegisterCustomFunction $0 "getIsHighContrast"
+
+ GetFunctionAddress $0 gotoInstallPage
+ WebBrowser::RegisterCustomFunction $0 "gotoInstallPage"
+
+ GetFunctionAddress $0 getProgressBarPercent
+ WebBrowser::RegisterCustomFunction $0 "getProgressBarPercent"
+!macroend
+!define RegisterAllCustomFunctions "!insertmacro _RegisterAllCustomFunctions"
+
+!macro _StartTimer _INTERVAL_MS _FUNCTION_NAME
+ Push $0
+ GetFunctionAddress $0 ${_FUNCTION_NAME}
+ WebBrowser::CreateTimer $0 ${_INTERVAL_MS}
+ Pop $TimerHandle
+ Pop $0
+!macroend
+!define StartTimer "!insertmacro _StartTimer"
+
+Function gotoInstallPage
+ Pop $0
+ StrCpy $CheckboxCleanupProfile $0
+
+ StrCpy $R9 1
+ Call RelativeGotoPage
+ Push $0
+FunctionEnd
+
+Function getProgressBarPercent
+ ; Custom functions always get one parameter, which we don't use here.
+ ; But we will use $0 as a scratch accumulator register.
+ Pop $0
+ ; This math is getting the progess bar completion fraction and converting it
+ ; to a percentage, but we implement that with the operations in the reverse
+ ; of the intuitive order so that our integer math doesn't truncate to zero.
+ IntOp $0 $ProgressCompleted * 100
+ IntOp $0 $0 / ${PROGRESS_BAR_TOTAL_STEPS}
+ Push $0
+FunctionEnd
+
+Function getTextDirection
+ Pop $0
+ !ifdef ${AB_CD}_rtl
+ Push "rtl"
+ !else
+ Push "ltr"
+ !endif
+FunctionEnd
+
+Function getFontName
+ Pop $0
+ Push $FontFamilyName
+FunctionEnd
+
+Function getIsHighContrast
+ Pop $0
+ Push $UsingHighContrastMode
+FunctionEnd
+
+Function getUIString
+ Pop $0
+ ${Select} $0
+ ${Case} "cleanup_header"
+ ${If} $ProfileCleanupPromptType == 1
+ Push "$(STUB_CLEANUP_REINSTALL_HEADER2)"
+ ${Else}
+ Push "$(STUB_CLEANUP_PAVEOVER_HEADER2)"
+ ${EndIf}
+ ${Case} "cleanup_button"
+ ${If} $ProfileCleanupPromptType == 1
+ Push "$(STUB_CLEANUP_REINSTALL_BUTTON2)"
+ ${Else}
+ Push "$(STUB_CLEANUP_PAVEOVER_BUTTON2)"
+ ${EndIf}
+ ${Case} "cleanup_checkbox"
+ Push "$(STUB_CLEANUP_CHECKBOX_LABEL2)"
+ ${Case} "installing_header"
+ Push "$(STUB_INSTALLING_HEADLINE2)"
+ ${Case} "installing_label"
+ Push "$(STUB_INSTALLING_LABEL2)"
+ ${Case} "installing_content"
+ Push "$(STUB_INSTALLING_BODY2)"
+ ${Case} "installing_blurb_0"
+ Push "$(STUB_BLURB_FIRST1)"
+ ${Case} "installing_blurb_1"
+ Push "$(STUB_BLURB_SECOND1)"
+ ${Case} "installing_blurb_2"
+ Push "$(STUB_BLURB_THIRD1)"
+ ${Case} "global_footer"
+ Push "$(STUB_BLURB_FOOTER2)"
+ ${Default}
+ Push ""
+ ${EndSelect}
+FunctionEnd
+
+Function createProfileCleanup
+ Call ShouldPromptForProfileCleanup
+
+ ${If} $ProfileCleanupPromptType == 0
+ StrCpy $CheckboxCleanupProfile 0
+ Abort ; Skip this page
+ ${EndIf}
+
+ ${RegisterAllCustomFunctions}
+
+ File /oname=$PLUGINSDIR\profile_cleanup.html "profile_cleanup.html"
+ File /oname=$PLUGINSDIR\profile_cleanup_page.css "profile_cleanup_page.css"
+ File /oname=$PLUGINSDIR\profile_cleanup.js "profile_cleanup.js"
+ WebBrowser::ShowPage "$PLUGINSDIR\profile_cleanup.html"
+FunctionEnd
+
+Function createInstall
+ GetDlgItem $0 $HWNDPARENT 1 ; Install button
+ EnableWindow $0 0
+ ShowWindow $0 ${SW_HIDE}
+
+ GetDlgItem $0 $HWNDPARENT 3 ; Back button
+ EnableWindow $0 0
+ ShowWindow $0 ${SW_HIDE}
+
+ GetDlgItem $0 $HWNDPARENT 2 ; Cancel button
+ ; Hide the Cancel button, but don't disable it (or else it won't be possible
+ ; to close the window)
+ ShowWindow $0 ${SW_HIDE}
+
+ ; Get keyboard focus on the parent
+ System::Call "user32::SetFocus(p$HWNDPARENT)"
+
+ ; Set $DownloadReset to true so the first download tick count is measured.
+ StrCpy $DownloadReset "true"
+ StrCpy $IsDownloadFinished "false"
+ StrCpy $DownloadRetryCount "0"
+ StrCpy $DownloadedBytes "0"
+ StrCpy $StartLastDownloadTickCount ""
+ StrCpy $DownloadFirstTransferSeconds ""
+ StrCpy $OpenedDownloadPage "0"
+
+ ClearErrors
+ ReadINIStr $ExistingVersion "$INSTDIR\application.ini" "App" "Version"
+ ${If} ${Errors}
+ StrCpy $ExistingVersion "0"
+ ${EndIf}
+
+ ClearErrors
+ ReadINIStr $ExistingBuildID "$INSTDIR\application.ini" "App" "BuildID"
+ ${If} ${Errors}
+ StrCpy $ExistingBuildID "0"
+ ${EndIf}
+
+ ${GetLocalAppDataFolder} $0
+ ${If} ${FileExists} "$0\Mozilla\Firefox"
+ StrCpy $ExistingProfile "1"
+ ${Else}
+ StrCpy $ExistingProfile "0"
+ ${EndIf}
+
+ StrCpy $DownloadServerIP ""
+
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $StartDownloadPhaseTickCount
+
+ ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log"
+ StrCpy $InstallTotalSteps ${InstallPaveOverTotalSteps}
+ ${Else}
+ StrCpy $InstallTotalSteps ${InstallCleanTotalSteps}
+ ${EndIf}
+
+ ${ITBL3Create}
+ ${ITBL3SetProgressState} "${TBPF_INDETERMINATE}"
+
+ ; Make sure the file we're about to try to download to doesn't already exist,
+ ; so we don't end up trying to "resume" on top of the wrong file.
+ Delete "$PLUGINSDIR\download.exe"
+
+ ${StartTimer} ${DownloadIntervalMS} StartDownload
+
+ ${RegisterAllCustomFunctions}
+
+ File /oname=$PLUGINSDIR\installing.html "installing.html"
+ File /oname=$PLUGINSDIR\installing_page.css "installing_page.css"
+ File /oname=$PLUGINSDIR\installing.js "installing.js"
+ WebBrowser::ShowPage "$PLUGINSDIR\installing.html"
+FunctionEnd
+
+Function StartDownload
+ WebBrowser::CancelTimer $TimerHandle
+
+ Call GetDownloadURL
+ Pop $0
+ InetBgDL::Get "$0" "$PLUGINSDIR\download.exe" \
+ /CONNECTTIMEOUT 120 /RECEIVETIMEOUT 120 /END
+
+ ${StartTimer} ${DownloadIntervalMS} OnDownload
+
+ ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"
+ RmDir /r "$INSTDIR\${TO_BE_DELETED}"
+ ${EndIf}
+FunctionEnd
+
+Function SetProgressBars
+ ${ITBL3SetProgressValue} "$ProgressCompleted" "${PROGRESS_BAR_TOTAL_STEPS}"
+FunctionEnd
+
+Function OnDownload
+ InetBgDL::GetStats
+ # $0 = HTTP status code, 0=Completed
+ # $1 = Completed files
+ # $2 = Remaining files
+ # $3 = Number of downloaded bytes for the current file
+ # $4 = Size of current file (Empty string if the size is unknown)
+ # /RESET must be used if status $0 > 299 (e.g. failure), even if resuming
+ # When status is $0 =< 299 it is handled by InetBgDL
+ StrCpy $DownloadServerIP "$5"
+ ${If} $0 > 299
+ WebBrowser::CancelTimer $TimerHandle
+ IntOp $DownloadRetryCount $DownloadRetryCount + 1
+ ${If} $DownloadRetryCount >= ${DownloadMaxRetries}
+ StrCpy $ExitCode "${ERR_DOWNLOAD_TOO_MANY_RETRIES}"
+ ; Use a timer so the UI has a chance to update
+ ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
+ Return
+ ${EndIf}
+
+ ; 1000 is a special code meaning InetBgDL lost the connection before it got
+ ; all the bytes it was expecting. We'll try to resume the transfer in that
+ ; case (assuming we aren't out of retries), so don't treat it as a reset
+ ; or clear the progress bar.
+ ${If} $0 != 1000
+ ${If} "$DownloadReset" != "true"
+ StrCpy $DownloadedBytes "0"
+ ${ITBL3SetProgressState} "${TBPF_INDETERMINATE}"
+ ${EndIf}
+ StrCpy $DownloadSizeBytes ""
+ StrCpy $DownloadReset "true"
+ Delete "$PLUGINSDIR\download.exe"
+ ${EndIf}
+
+ InetBgDL::Get /RESET /END
+ ${StartTimer} ${DownloadRetryIntervalMS} StartDownload
+ Return
+ ${EndIf}
+
+ ${If} "$DownloadReset" == "true"
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $StartLastDownloadTickCount
+ StrCpy $DownloadReset "false"
+ ; The seconds elapsed from the start of the download phase until the first
+ ; bytes are received are only recorded for the first request so it is
+ ; possible to determine connection issues for the first request.
+ ${If} "$DownloadFirstTransferSeconds" == ""
+ ; Get the seconds elapsed from the start of the download phase until the
+ ; first bytes are received.
+ ${GetSecondsElapsed} "$StartDownloadPhaseTickCount" "$StartLastDownloadTickCount" $DownloadFirstTransferSeconds
+ ${EndIf}
+ ${EndIf}
+
+ ${If} "$DownloadSizeBytes" == ""
+ ${AndIf} "$4" != ""
+ StrCpy $DownloadSizeBytes "$4"
+ StrCpy $ProgressCompleted 0
+ ${EndIf}
+
+ ; Don't update the status until after the download starts
+ ${If} $2 != 0
+ ${AndIf} "$4" == ""
+ Return
+ ${EndIf}
+
+ ${If} $IsDownloadFinished != "true"
+ ${If} $2 == 0
+ WebBrowser::CancelTimer $TimerHandle
+ StrCpy $IsDownloadFinished "true"
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $EndDownloadPhaseTickCount
+
+ ${If} "$DownloadSizeBytes" == ""
+ ; It's possible for the download to finish before we were able to
+ ; get the size while it was downloading, and InetBgDL doesn't report
+ ; it afterwards. Use the size of the finished file.
+ ClearErrors
+ FileOpen $5 "$PLUGINSDIR\download.exe" r
+ ${IfNot} ${Errors}
+ FileSeek $5 0 END $DownloadSizeBytes
+ FileClose $5
+ ${EndIf}
+ ${EndIf}
+ StrCpy $DownloadedBytes "$DownloadSizeBytes"
+
+ ; Update the progress bars first in the UI change so they take affect
+ ; before other UI changes.
+ StrCpy $ProgressCompleted "${PROGRESS_BAR_DOWNLOAD_END_STEP}"
+ Call SetProgressBars
+
+ ; Disable the Cancel button during the install
+ GetDlgItem $5 $HWNDPARENT 2
+ EnableWindow $5 0
+
+ ; Open a handle to prevent modification of the full installer
+ StrCpy $R9 "${INVALID_HANDLE_VALUE}"
+ System::Call 'kernel32::CreateFileW(w "$PLUGINSDIR\download.exe", \
+ i ${GENERIC_READ}, \
+ i ${FILE_SHARE_READ}, i 0, \
+ i ${OPEN_EXISTING}, i 0, i 0) i .R9'
+ StrCpy $HandleDownload "$R9"
+
+ ${If} $HandleDownload == ${INVALID_HANDLE_VALUE}
+ StrCpy $ExitCode "${ERR_PREINSTALL_INVALID_HANDLE}"
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $EndPreInstallPhaseTickCount
+ ; Use a timer so the UI has a chance to update
+ ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
+ ${Else}
+ CertCheck::CheckPETrustAndInfoAsync "$PLUGINSDIR\download.exe" \
+ "${CertNameDownload}" "${CertIssuerDownload}"
+ ${StartTimer} ${DownloadIntervalMS} OnCertCheck
+ ${EndIf}
+ ${Else}
+ StrCpy $DownloadedBytes "$3"
+ System::Int64Op $DownloadedBytes * ${PROGRESS_BAR_DOWNLOAD_END_STEP}
+ Pop $ProgressCompleted
+ System::Int64Op $ProgressCompleted / $DownloadSizeBytes
+ Pop $ProgressCompleted
+ Call SetProgressBars
+ ${EndIf}
+ ${EndIf}
+FunctionEnd
+
+Function OnCertCheck
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $EndPreInstallPhaseTickCount
+
+ CertCheck::GetStatus
+ Pop $0
+ ${If} $0 == 0
+ ${GetSecondsElapsed} "$EndDownloadPhaseTickCount" "$EndPreInstallPhaseTickCount" $0
+ ${If} $0 >= ${PreinstallCertCheckMaxWaitSec}
+ WebBrowser::CancelTimer $TimerHandle
+ StrCpy $ExitCode "${ERR_PREINSTALL_CERT_TIMEOUT}"
+ ; Use a timer so the UI has a chance to update
+ ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
+ ${EndIf}
+ Return
+ ${EndIf}
+ Pop $0
+ Pop $1
+
+ ${If} $0 == 0
+ ${AndIf} $1 == 0
+ StrCpy $ExitCode "${ERR_PREINSTALL_CERT_UNTRUSTED_AND_ATTRIBUTES}"
+ ${ElseIf} $0 == 0
+ StrCpy $ExitCode "${ERR_PREINSTALL_CERT_UNTRUSTED}"
+ ${ElseIf} $1 == 0
+ StrCpy $ExitCode "${ERR_PREINSTALL_CERT_ATTRIBUTES}"
+ ${EndIf}
+
+ WebBrowser::CancelTimer $TimerHandle
+
+ ${If} $0 == 0
+ ${OrIf} $1 == 0
+ ; Use a timer so the UI has a chance to update
+ ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
+ Return
+ ${EndIf}
+
+ Call LaunchFullInstaller
+FunctionEnd
+
+Function LaunchFullInstaller
+ ; Instead of extracting the files we use the downloaded installer to
+ ; install in case it needs to perform operations that the stub doesn't
+ ; know about.
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "InstallDirectoryPath" "$INSTDIR"
+ ; Don't create the QuickLaunch or Taskbar shortcut from the launched installer
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "QuickLaunchShortcut" "false"
+
+ ; Always create a start menu shortcut, so the user always has some way
+ ; to access the application.
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "StartMenuShortcuts" "true"
+
+ ; Either avoid or force adding a taskbar pin and desktop shortcut
+ ; based on the checkbox value.
+ ${If} $CheckboxShortcuts == 0
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "TaskbarShortcut" "false"
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "false"
+ ${Else}
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "TaskbarShortcut" "true"
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "true"
+ ${EndIf}
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+ ${If} $CheckboxInstallMaintSvc == 1
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "true"
+ ${Else}
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
+ ${EndIf}
+!else
+ WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
+!endif
+
+ ; Delete the taskbar shortcut history to ensure we do the right thing based on
+ ; the config file above.
+ ${GetShortcutsLogPath} $0
+ Delete "$0"
+
+ ${RemovePrecompleteEntries} "false"
+
+ ; Delete the install.log and let the full installer create it. When the
+ ; installer closes it we can detect that it has completed.
+ Delete "$INSTDIR\install.log"
+
+ ; Delete firefox.exe.moz-upgrade and firefox.exe.moz-delete if it exists
+ ; since it being present will require an OS restart for the full
+ ; installer.
+ Delete "$INSTDIR\${FileMainEXE}.moz-upgrade"
+ Delete "$INSTDIR\${FileMainEXE}.moz-delete"
+
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $EndPreInstallPhaseTickCount
+
+ Exec "$\"$PLUGINSDIR\download.exe$\" /LaunchedFromStub /INI=$PLUGINSDIR\${CONFIG_INI}"
+ ${StartTimer} ${InstallIntervalMS} CheckInstall
+FunctionEnd
+
+Function SendPing
+ HideWindow
+
+ ${If} $CheckboxSendPing == 1
+ ; Get the tick count for the completion of all phases.
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $EndFinishPhaseTickCount
+
+ ; When the value of $IsDownloadFinished is false the download was started
+ ; but didn't finish. In this case the tick count stored in
+ ; $EndFinishPhaseTickCount is used to determine how long the download was
+ ; in progress.
+ ${If} "$IsDownloadFinished" == "false"
+ StrCpy $EndDownloadPhaseTickCount "$EndFinishPhaseTickCount"
+ ; Cancel the download in progress
+ InetBgDL::Get /RESET /END
+ ${EndIf}
+
+
+ ; When $DownloadFirstTransferSeconds equals an empty string the download
+ ; never successfully started so set the value to 0. It will be possible to
+ ; determine that the download didn't successfully start from the seconds for
+ ; the last download.
+ ${If} "$DownloadFirstTransferSeconds" == ""
+ StrCpy $DownloadFirstTransferSeconds "0"
+ ${EndIf}
+
+ ; When $StartLastDownloadTickCount equals an empty string the download never
+ ; successfully started so set the value to $EndDownloadPhaseTickCount to
+ ; compute the correct value.
+ ${If} $StartLastDownloadTickCount == ""
+ ; This could happen if the download never successfully starts
+ StrCpy $StartLastDownloadTickCount "$EndDownloadPhaseTickCount"
+ ${EndIf}
+
+ ; When $EndPreInstallPhaseTickCount equals 0 the installation phase was
+ ; never completed so set its value to $EndFinishPhaseTickCount to compute
+ ; the correct value.
+ ${If} "$EndPreInstallPhaseTickCount" == "0"
+ StrCpy $EndPreInstallPhaseTickCount "$EndFinishPhaseTickCount"
+ ${EndIf}
+
+ ; When $EndInstallPhaseTickCount equals 0 the installation phase was never
+ ; completed so set its value to $EndFinishPhaseTickCount to compute the
+ ; correct value.
+ ${If} "$EndInstallPhaseTickCount" == "0"
+ StrCpy $EndInstallPhaseTickCount "$EndFinishPhaseTickCount"
+ ${EndIf}
+
+ ; Get the seconds elapsed from the start of the download phase to the end of
+ ; the download phase.
+ ${GetSecondsElapsed} "$StartDownloadPhaseTickCount" "$EndDownloadPhaseTickCount" $0
+
+ ; Get the seconds elapsed from the start of the last download to the end of
+ ; the last download.
+ ${GetSecondsElapsed} "$StartLastDownloadTickCount" "$EndDownloadPhaseTickCount" $1
+
+ ; Get the seconds elapsed from the end of the download phase to the
+ ; completion of the pre-installation check phase.
+ ${GetSecondsElapsed} "$EndDownloadPhaseTickCount" "$EndPreInstallPhaseTickCount" $2
+
+ ; Get the seconds elapsed from the end of the pre-installation check phase
+ ; to the completion of the installation phase.
+ ${GetSecondsElapsed} "$EndPreInstallPhaseTickCount" "$EndInstallPhaseTickCount" $3
+
+ ; Get the seconds elapsed from the end of the installation phase to the
+ ; completion of all phases.
+ ${GetSecondsElapsed} "$EndInstallPhaseTickCount" "$EndFinishPhaseTickCount" $4
+
+ ${If} $ArchToInstall == ${ARCH_AMD64}
+ ${OrIf} $ArchToInstall == ${ARCH_AARCH64}
+ StrCpy $R0 "1"
+ ${Else}
+ StrCpy $R0 "0"
+ ${EndIf}
+
+ ${If} ${IsNativeAMD64}
+ ${OrIf} ${IsNativeARM64}
+ StrCpy $R1 "1"
+ ${Else}
+ StrCpy $R1 "0"
+ ${EndIf}
+
+ ; Though these values are sometimes incorrect due to bug 444664 it happens
+ ; so rarely it isn't worth working around it by reading the registry values.
+ ${WinVerGetMajor} $5
+ ${WinVerGetMinor} $6
+ ${WinVerGetBuild} $7
+ ${WinVerGetServicePackLevel} $8
+ ${If} ${IsServerOS}
+ StrCpy $9 "1"
+ ${Else}
+ StrCpy $9 "0"
+ ${EndIf}
+
+ ${If} "$ExitCode" == "${ERR_SUCCESS}"
+ ReadINIStr $R5 "$INSTDIR\application.ini" "App" "Version"
+ ReadINIStr $R6 "$INSTDIR\application.ini" "App" "BuildID"
+ ${Else}
+ StrCpy $R5 "0"
+ StrCpy $R6 "0"
+ ${EndIf}
+
+ ; Whether installed into the default installation directory
+ ${GetLongPath} "$INSTDIR" $R7
+ ${GetLongPath} "$InitialInstallDir" $R8
+ ${If} "$R7" == "$R8"
+ StrCpy $R7 "1"
+ ${Else}
+ StrCpy $R7 "0"
+ ${EndIf}
+
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" \
+ "Write Test"
+ ${If} ${Errors}
+ StrCpy $R8 "0"
+ ${Else}
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ StrCpy $R8 "1"
+ ${EndIf}
+
+ ${If} "$DownloadServerIP" == ""
+ StrCpy $DownloadServerIP "Unknown"
+ ${EndIf}
+
+ StrCpy $R2 ""
+ SetShellVarContext current ; Set SHCTX to the current user
+ ReadRegStr $R2 HKCU "Software\Classes\http\shell\open\command" ""
+ ${If} $R2 != ""
+ ${GetPathFromString} "$R2" $R2
+ ${GetParent} "$R2" $R3
+ ${GetLongPath} "$R3" $R3
+ ${If} $R3 == $INSTDIR
+ StrCpy $R2 "1" ; This Firefox install is set as default.
+ ${Else}
+ StrCpy $R2 "$R2" "" -11 # length of firefox.exe
+ ${If} "$R2" == "${FileMainEXE}"
+ StrCpy $R2 "2" ; Another Firefox install is set as default.
+ ${Else}
+ StrCpy $R2 "0"
+ ${EndIf}
+ ${EndIf}
+ ${Else}
+ StrCpy $R2 "0" ; Firefox is not set as default.
+ ${EndIf}
+
+ ${If} "$R2" == "0"
+ StrCpy $R3 ""
+ ReadRegStr $R2 HKLM "Software\Classes\http\shell\open\command" ""
+ ${If} $R2 != ""
+ ${GetPathFromString} "$R2" $R2
+ ${GetParent} "$R2" $R3
+ ${GetLongPath} "$R3" $R3
+ ${If} $R3 == $INSTDIR
+ StrCpy $R2 "1" ; This Firefox install is set as default.
+ ${Else}
+ StrCpy $R2 "$R2" "" -11 # length of firefox.exe
+ ${If} "$R2" == "${FileMainEXE}"
+ StrCpy $R2 "2" ; Another Firefox install is set as default.
+ ${Else}
+ StrCpy $R2 "0"
+ ${EndIf}
+ ${EndIf}
+ ${Else}
+ StrCpy $R2 "0" ; Firefox is not set as default.
+ ${EndIf}
+ ${EndIf}
+
+ ${If} $CanSetAsDefault == "true"
+ ${If} $CheckboxSetAsDefault == "1"
+ StrCpy $R3 "2"
+ ${Else}
+ StrCpy $R3 "3"
+ ${EndIf}
+ ${Else}
+ ${If} ${AtLeastWin8}
+ StrCpy $R3 "1"
+ ${Else}
+ StrCpy $R3 "0"
+ ${EndIf}
+ ${EndIf}
+
+!ifdef STUB_DEBUG
+ MessageBox MB_OK "${BaseURLStubPing} \
+ $\nStub URL Version = ${StubURLVersion}${StubURLVersionAppend} \
+ $\nBuild Channel = ${Channel} \
+ $\nUpdate Channel = ${UpdateChannel} \
+ $\nLocale = ${AB_CD} \
+ $\nFirefox x64 = $R0 \
+ $\nRunning x64 Windows = $R1 \
+ $\nMajor = $5 \
+ $\nMinor = $6 \
+ $\nBuild = $7 \
+ $\nServicePack = $8 \
+ $\nIsServer = $9 \
+ $\nExit Code = $ExitCode \
+ $\nFirefox Launch Code = $FirefoxLaunchCode \
+ $\nDownload Retry Count = $DownloadRetryCount \
+ $\nDownloaded Bytes = $DownloadedBytes \
+ $\nDownload Size Bytes = $DownloadSizeBytes \
+ $\nIntroduction Phase Seconds = $IntroPhaseSeconds \
+ $\nOptions Phase Seconds = $OptionsPhaseSeconds \
+ $\nDownload Phase Seconds = $0 \
+ $\nLast Download Seconds = $1 \
+ $\nDownload First Transfer Seconds = $DownloadFirstTransferSeconds \
+ $\nPreinstall Phase Seconds = $2 \
+ $\nInstall Phase Seconds = $3 \
+ $\nFinish Phase Seconds = $4 \
+ $\nInitial Install Requirements Code = $InitialInstallRequirementsCode \
+ $\nOpened Download Page = $OpenedDownloadPage \
+ $\nExisting Profile = $ExistingProfile \
+ $\nExisting Version = $ExistingVersion \
+ $\nExisting Build ID = $ExistingBuildID \
+ $\nNew Version = $R5 \
+ $\nNew Build ID = $R6 \
+ $\nDefault Install Dir = $R7 \
+ $\nHas Admin = $R8 \
+ $\nDefault Status = $R2 \
+ $\nSet As Sefault Status = $R3 \
+ $\nDownload Server IP = $DownloadServerIP \
+ $\nPost-Signing Data = $PostSigningData \
+ $\nProfile cleanup prompt shown = $ProfileCleanupPromptType \
+ $\nDid profile cleanup = $CheckboxCleanupProfile"
+ ; The following will exit the installer
+ SetAutoClose true
+ StrCpy $R9 "2"
+ Call RelativeGotoPage
+!else
+ ${StartTimer} ${DownloadIntervalMS} OnPing
+ InetBgDL::Get "${BaseURLStubPing}/${StubURLVersion}${StubURLVersionAppend}/${Channel}/${UpdateChannel}/${AB_CD}/$R0/$R1/$5/$6/$7/$8/$9/$ExitCode/$FirefoxLaunchCode/$DownloadRetryCount/$DownloadedBytes/$DownloadSizeBytes/$IntroPhaseSeconds/$OptionsPhaseSeconds/$0/$1/$DownloadFirstTransferSeconds/$2/$3/$4/$InitialInstallRequirementsCode/$OpenedDownloadPage/$ExistingProfile/$ExistingVersion/$ExistingBuildID/$R5/$R6/$R7/$R8/$R2/$R3/$DownloadServerIP/$PostSigningData/$ProfileCleanupPromptType/$CheckboxCleanupProfile" \
+ "$PLUGINSDIR\_temp" /END
+!endif
+ ${Else}
+ ${If} "$IsDownloadFinished" == "false"
+ ; Cancel the download in progress
+ InetBgDL::Get /RESET /END
+ ${EndIf}
+ ; The following will exit the installer
+ SetAutoClose true
+ StrCpy $R9 "2"
+ Call RelativeGotoPage
+ ${EndIf}
+FunctionEnd
+
+Function OnPing
+ InetBgDL::GetStats
+ # $0 = HTTP status code, 0=Completed
+ # $1 = Completed files
+ # $2 = Remaining files
+ # $3 = Number of downloaded bytes for the current file
+ # $4 = Size of current file (Empty string if the size is unknown)
+ # /RESET must be used if status $0 > 299 (e.g. failure)
+ # When status is $0 =< 299 it is handled by InetBgDL
+ ${If} $2 == 0
+ ${OrIf} $0 > 299
+ WebBrowser::CancelTimer $TimerHandle
+ ${If} $0 > 299
+ InetBgDL::Get /RESET /END
+ ${EndIf}
+ ; The following will exit the installer
+ SetAutoClose true
+ StrCpy $R9 "2"
+ Call RelativeGotoPage
+ ${EndIf}
+FunctionEnd
+
+Function CheckInstall
+ IntOp $InstallCounterStep $InstallCounterStep + 1
+ ${If} $InstallCounterStep >= $InstallTotalSteps
+ WebBrowser::CancelTimer $TimerHandle
+ ; Close the handle that prevents modification of the full installer
+ System::Call 'kernel32::CloseHandle(i $HandleDownload)'
+ StrCpy $ExitCode "${ERR_INSTALL_TIMEOUT}"
+ ; Use a timer so the UI has a chance to update
+ ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
+ Return
+ ${EndIf}
+
+ ${If} $ProgressCompleted < ${PROGRESS_BAR_INSTALL_END_STEP}
+ IntOp $0 ${PROGRESS_BAR_INSTALL_END_STEP} - ${PROGRESS_BAR_DOWNLOAD_END_STEP}
+ IntOp $0 $InstallCounterStep * $0
+ IntOp $0 $0 / $InstallTotalSteps
+ IntOp $ProgressCompleted ${PROGRESS_BAR_DOWNLOAD_END_STEP} + $0
+ Call SetProgressBars
+ ${EndIf}
+
+ ${If} ${FileExists} "$INSTDIR\install.log"
+ Delete "$INSTDIR\install.tmp"
+ CopyFiles /SILENT "$INSTDIR\install.log" "$INSTDIR\install.tmp"
+
+ ; The unfocus and refocus that happens approximately here is caused by the
+ ; installer calling RefreshShellIcons to refresh the shortcut icons.
+
+ ; When the full installer completes the installation the install.log will no
+ ; longer be in use.
+ ClearErrors
+ Delete "$INSTDIR\install.log"
+ ${Unless} ${Errors}
+ WebBrowser::CancelTimer $TimerHandle
+ ; Close the handle that prevents modification of the full installer
+ System::Call 'kernel32::CloseHandle(i $HandleDownload)'
+ Rename "$INSTDIR\install.tmp" "$INSTDIR\install.log"
+ Delete "$PLUGINSDIR\download.exe"
+ Delete "$PLUGINSDIR\${CONFIG_INI}"
+ System::Call "kernel32::GetTickCount()l .s"
+ Pop $EndInstallPhaseTickCount
+ Call FinishInstall
+ ${EndUnless}
+ ${EndIf}
+FunctionEnd
+
+Function FinishInstall
+ StrCpy $ProgressCompleted "${PROGRESS_BAR_INSTALL_END_STEP}"
+ Call SetProgressBars
+
+ ${If} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-upgrade"
+ Delete "$INSTDIR\${FileMainEXE}"
+ Rename "$INSTDIR\${FileMainEXE}.moz-upgrade" "$INSTDIR\${FileMainEXE}"
+ ${EndIf}
+
+ StrCpy $ExitCode "${ERR_SUCCESS}"
+
+ ${CopyPostSigningData}
+ Pop $PostSigningData
+
+ Call LaunchApp
+FunctionEnd
+
+Function RelativeGotoPage
+ IntCmp $R9 0 0 Move Move
+ StrCmp $R9 "X" 0 Move
+ StrCpy $R9 "120"
+
+ Move:
+ SendMessage $HWNDPARENT "0x408" "$R9" ""
+FunctionEnd
+
+Function CheckSpace
+ ${If} "$ExistingTopDir" != ""
+ StrLen $0 "$ExistingTopDir"
+ StrLen $1 "$INSTDIR"
+ ${If} $0 <= $1
+ StrCpy $2 "$INSTDIR" $3
+ ${If} "$2" == "$ExistingTopDir"
+ Return
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+
+ StrCpy $ExistingTopDir "$INSTDIR"
+ ${DoUntil} ${FileExists} "$ExistingTopDir"
+ ${GetParent} "$ExistingTopDir" $ExistingTopDir
+ ${If} "$ExistingTopDir" == ""
+ StrCpy $SpaceAvailableBytes "0"
+ StrCpy $HasRequiredSpaceAvailable "false"
+ Return
+ ${EndIf}
+ ${Loop}
+
+ ${GetLongPath} "$ExistingTopDir" $ExistingTopDir
+
+ ; GetDiskFreeSpaceExW requires a backslash.
+ StrCpy $0 "$ExistingTopDir" "" -1 ; the last character
+ ${If} "$0" != "\"
+ StrCpy $0 "\"
+ ${Else}
+ StrCpy $0 ""
+ ${EndIf}
+
+ System::Call 'kernel32::GetDiskFreeSpaceExW(w, *l, *l, *l) i("$ExistingTopDir$0", .r1, .r2, .r3) .'
+ StrCpy $SpaceAvailableBytes "$1"
+
+ System::Int64Op $SpaceAvailableBytes / 1048576
+ Pop $1
+ System::Int64Op $1 > ${APPROXIMATE_REQUIRED_SPACE_MB}
+ Pop $1
+ ${If} $1 == 1
+ StrCpy $HasRequiredSpaceAvailable "true"
+ ${Else}
+ StrCpy $HasRequiredSpaceAvailable "false"
+ ${EndIf}
+FunctionEnd
+
+Function CanWrite
+ StrCpy $CanWriteToInstallDir "false"
+
+ StrCpy $0 "$INSTDIR"
+ ; Use the existing directory when it exists
+ ${Unless} ${FileExists} "$INSTDIR"
+ ; Get the topmost directory that exists for new installs
+ ${DoUntil} ${FileExists} "$0"
+ ${GetParent} "$0" $0
+ ${If} "$0" == ""
+ Return
+ ${EndIf}
+ ${Loop}
+ ${EndUnless}
+
+ GetTempFileName $2 "$0"
+ Delete $2
+ CreateDirectory "$2"
+
+ ${If} ${FileExists} "$2"
+ ${If} ${FileExists} "$INSTDIR"
+ GetTempFileName $3 "$INSTDIR"
+ ${Else}
+ GetTempFileName $3 "$2"
+ ${EndIf}
+ ${If} ${FileExists} "$3"
+ Delete "$3"
+ StrCpy $CanWriteToInstallDir "true"
+ ${EndIf}
+ RmDir "$2"
+ ${EndIf}
+FunctionEnd
+
+Function LaunchApp
+ StrCpy $FirefoxLaunchCode "2"
+
+ ; Set the current working directory to the installation directory
+ SetOutPath "$INSTDIR"
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $1
+ ${If} ${Errors}
+ ${If} $CheckboxCleanupProfile == 1
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -reset-profile -migration -first-startup"
+ ${Else}
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -first-startup"
+ ${EndIf}
+ ${Else}
+ StrCpy $R1 $CheckboxCleanupProfile
+ GetFunctionAddress $0 LaunchAppFromElevatedProcess
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+
+ StrCpy $AppLaunchWaitTickCount 0
+ ${StartTimer} ${AppLaunchWaitIntervalMS} WaitForAppLaunch
+FunctionEnd
+
+Function LaunchAppFromElevatedProcess
+ ; Set the current working directory to the installation directory
+ SetOutPath "$INSTDIR"
+ ${If} $R1 == 1
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -reset-profile -migration -first-startup"
+ ${Else}
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -first-startup"
+ ${EndIf}
+FunctionEnd
+
+Function WaitForAppLaunch
+ FindWindow $0 "${MainWindowClass}"
+ FindWindow $1 "${DialogWindowClass}"
+ ${If} $0 <> 0
+ ${OrIf} $1 <> 0
+ WebBrowser::CancelTimer $TimerHandle
+ StrCpy $ProgressCompleted "${PROGRESS_BAR_APP_LAUNCH_END_STEP}"
+ Call SetProgressBars
+ Call SendPing
+ Return
+ ${EndIf}
+
+ IntOp $AppLaunchWaitTickCount $AppLaunchWaitTickCount + 1
+ IntOp $0 $AppLaunchWaitTickCount * ${AppLaunchWaitIntervalMS}
+ ${If} $0 >= ${AppLaunchWaitTimeoutMS}
+ ; We've waited an unreasonably long time, so just exit.
+ WebBrowser::CancelTimer $TimerHandle
+ Call SendPing
+ Return
+ ${EndIf}
+
+ ${If} $ProgressCompleted < ${PROGRESS_BAR_APP_LAUNCH_END_STEP}
+ IntOp $ProgressCompleted $ProgressCompleted + 1
+ Call SetProgressBars
+ ${EndIf}
+FunctionEnd
+
+Function DisplayDownloadError
+ WebBrowser::CancelTimer $TimerHandle
+ ; To better display the error state on the taskbar set the progress completed
+ ; value to the total value.
+ ${ITBL3SetProgressValue} "100" "100"
+ ${ITBL3SetProgressState} "${TBPF_ERROR}"
+
+ MessageBox MB_OKCANCEL|MB_ICONSTOP "$(ERROR_DOWNLOAD_CONT)" IDCANCEL +2 IDOK +1
+ Call LaunchHelpPage
+ Call SendPing
+FunctionEnd
+
+Function LaunchHelpPage
+ StrCpy $OpenedDownloadPage "1" ; Already initialized to 0
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $1
+ ${If} ${Errors}
+ Call OpenManualDownloadURL
+ ${Else}
+ GetFunctionAddress $0 OpenManualDownloadURL
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+FunctionEnd
+
+Function OpenManualDownloadURL
+ ClearErrors
+ ReadINIStr $0 "${PARTNER_INI}" "DownloadURL" "FallbackPage"
+ ${IfNot} ${Errors}
+ ExecShell "open" "$0"
+ ${Else}
+ ExecShell "open" "${URLManualDownload}${URLManualDownloadAppend}"
+ ${EndIf}
+FunctionEnd
+
+Function ShouldPromptForProfileCleanup
+ ; This will be our return value.
+ StrCpy $ProfileCleanupPromptType 0
+
+ ; Only consider installations of the same architecture we're installing.
+ ${If} $ArchToInstall == ${ARCH_AMD64}
+ ${OrIf} $ArchToInstall == ${ARCH_AARCH64}
+ SetRegView 64
+ ${Else}
+ SetRegView 32
+ ${EndIf}
+
+ ; Make sure $APPDATA is the user's AppData and not ProgramData.
+ ; We'll set this back to all at the end of the function.
+ SetShellVarContext current
+
+ ${FindInstallSpecificProfile}
+ Pop $R0
+
+ ${If} $R0 == ""
+ ; We don't have an install-specific profile, so look for an old-style
+ ; default profile instead by checking each numbered Profile section.
+ StrCpy $0 0
+ ${Do}
+ ClearErrors
+ ; Check if the section exists by reading a value that must be present.
+ ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "Path"
+ ${If} ${Errors}
+ ; We've run out of profile sections.
+ ${Break}
+ ${EndIf}
+
+ ClearErrors
+ ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "Default"
+ ${IfNot} ${Errors}
+ ${AndIf} $1 == "1"
+ ; We've found the default profile
+ ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "Path"
+ ReadINIStr $2 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "IsRelative"
+ ${If} $2 == "1"
+ StrCpy $R0 "$APPDATA\Mozilla\Firefox\$1"
+ ${Else}
+ StrCpy $R0 "$1"
+ ${EndIf}
+ ${Break}
+ ${EndIf}
+
+ IntOp $0 $0 + 1
+ ${Loop}
+ ${EndIf}
+
+ GetFullPathName $R0 $R0
+
+ ${If} $R0 == ""
+ ; No profile to clean up, so don't show the cleanup prompt.
+ GoTo end
+ ${EndIf}
+
+ ; We have at least one profile present. If we don't have any installations,
+ ; then we need to show the re-install prompt. We'll say there's an
+ ; installation present if HKCR\FirefoxURL* exists and points to a real path.
+ StrCpy $0 0
+ StrCpy $R9 ""
+ ${Do}
+ ClearErrors
+ EnumRegKey $1 HKCR "" $0
+ ${If} ${Errors}
+ ${OrIf} $1 == ""
+ ${Break}
+ ${EndIf}
+ ${WordFind} "$1" "-" "+1{" $2
+ ${If} $2 == "FirefoxURL"
+ ClearErrors
+ ReadRegStr $2 HKCR "$1\DefaultIcon" ""
+ ${IfNot} ${Errors}
+ ${GetPathFromString} $2 $1
+ ${If} ${FileExists} $1
+ StrCpy $R9 $1
+ ${Break}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+ IntOp $0 $0 + 1
+ ${Loop}
+ ${If} $R9 == ""
+ StrCpy $ProfileCleanupPromptType 1
+ GoTo end
+ ${EndIf}
+
+ ; Okay, there's at least one install, let's see if it's for this channel.
+ SetShellVarContext all
+ ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $0
+ ${If} $0 == "false"
+ SetShellVarContext current
+ ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $0
+ ${If} $0 == "false"
+ ; Existing installs are not for this channel. Don't show any prompt.
+ GoTo end
+ ${EndIf}
+ ${EndIf}
+
+ ; Find out what version the default profile was last used on.
+ ${If} ${FileExists} "$R0\compatibility.ini"
+ ClearErrors
+ ReadINIStr $0 "$R0\compatibility.ini" "Compatibility" "LastVersion"
+ ${If} ${Errors}
+ GoTo end
+ ${EndIf}
+ ${WordFind} $0 "." "+1{" $0
+
+ ; We don't know what version we're about to install because we haven't
+ ; downloaded it yet. Find out what the latest version released on this
+ ; channel is and assume we'll be installing that one.
+ Call GetLatestReleasedVersion
+ ${If} ${Errors}
+ ; Use this stub installer's version as a fallback when we can't get the
+ ; real current version; this may be behind, but it's better than nothing.
+ StrCpy $1 ${AppVersion}
+ ${EndIf}
+
+ ${WordFind} $1 "." "+1{" $1
+ IntOp $1 $1 - 2
+
+ ${If} $1 > $0
+ ; Default profile was last used more than two versions ago, so we need
+ ; to show the paveover version of the profile cleanup prompt.
+ StrCpy $ProfileCleanupPromptType 2
+ ${EndIf}
+ ${EndIf}
+
+ end:
+ SetRegView lastused
+ SetShellVarContext all
+FunctionEnd
+
+Function GetLatestReleasedVersion
+ ClearErrors
+ Push $0 ; InetBgDl::GetStats uses $0 for the HTTP error code
+ ; $1 is our return value, so don't save it
+ Push $2 ; InetBgDl::GetStats uses $2 to tell us when the transfer is done
+ Push $3 ; $3 - $5 are also set by InetBgDl::GetStats, but we don't use them
+ Push $4
+ Push $5
+ Push $6 ; This is our response timeout counter
+
+ InetBgDL::Get /RESET /END
+ InetBgDL::Get "https://product-details.mozilla.org/1.0/firefox_versions.json" \
+ "$PLUGINSDIR\firefox_versions.json" \
+ /CONNECTTIMEOUT 120 /RECEIVETIMEOUT 120 /END
+
+ ; Wait for the response, but only give it half a second since this is on the
+ ; installer startup path (we haven't even shown a window yet).
+ StrCpy $6 0
+ ${Do}
+ Sleep 100
+ InetBgDL::GetStats
+ IntOp $6 $6 + 1
+
+ ${If} $2 == 0
+ ${Break}
+ ${ElseIf} $6 >= 5
+ InetBgDL::Get /RESET /END
+ SetErrors
+ GoTo end
+ ${EndIf}
+ ${Loop}
+
+ StrCpy $1 0
+ nsJSON::Set /file "$PLUGINSDIR\firefox_versions.json"
+ IfErrors end
+ ${Select} ${Channel}
+ ${Case} "unofficial"
+ StrCpy $1 "FIREFOX_NIGHTLY"
+ ${Case} "nightly"
+ StrCpy $1 "FIREFOX_NIGHTLY"
+ ${Case} "aurora"
+ StrCpy $1 "FIREFOX_DEVEDITION"
+ ${Case} "beta"
+ StrCpy $1 "LATEST_FIREFOX_RELEASED_DEVEL_VERSION"
+ ${Case} "release"
+ StrCpy $1 "LATEST_FIREFOX_VERSION"
+ ${EndSelect}
+ nsJSON::Get $1 /end
+
+ end:
+ ${If} ${Errors}
+ ${OrIf} $1 == 0
+ SetErrors
+ StrCpy $1 0
+ ${Else}
+ Pop $1
+ ${EndIf}
+
+ Pop $6
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $0
+FunctionEnd
+
+; Determine which architecture build we should download and install.
+; AArch64 is always selected if it's the native architecture of the machine.
+; Otherwise, we check a few things to determine if AMD64 is appropriate:
+; 1) Running a 64-bit OS (we've already checked the OS version).
+; 2) An amount of RAM strictly greater than RAM_NEEDED_FOR_64BIT
+; 3) No third-party products installed that cause issues with the 64-bit build.
+; Currently this includes Lenovo OneKey Theater and Lenovo Energy Management.
+; We also make sure that the partner.ini file contains a download URL for the
+; selected architecture, when a partner.ini file eixsts.
+; If any of those checks fail, the 32-bit x86 build is selected.
+Function GetArchToInstall
+ StrCpy $ArchToInstall ${ARCH_X86}
+
+ ${If} ${IsNativeARM64}
+ StrCpy $ArchToInstall ${ARCH_AARCH64}
+ GoTo downloadUrlCheck
+ ${EndIf}
+
+ ${IfNot} ${IsNativeAMD64}
+ Return
+ ${EndIf}
+
+ System::Call "*(i 64, i, l 0, l, l, l, l, l, l)p.r1"
+ System::Call "Kernel32::GlobalMemoryStatusEx(p r1)"
+ System::Call "*$1(i, i, l.r2, l, l, l, l, l, l)"
+ System::Free $1
+ ${If} $2 L<= ${RAM_NEEDED_FOR_64BIT}
+ Return
+ ${EndIf}
+
+ ; Lenovo OneKey Theater can theoretically be in a directory other than this
+ ; one, because some installer versions let you change it, but it's unlikely.
+ ${If} ${FileExists} "$PROGRAMFILES32\Lenovo\Onekey Theater\windowsapihookdll64.dll"
+ Return
+ ${EndIf}
+
+ ${If} ${FileExists} "$PROGRAMFILES32\Lenovo\Energy Management\Energy Management.exe"
+ Return
+ ${EndIf}
+
+ StrCpy $ArchToInstall ${ARCH_AMD64}
+
+ downloadUrlCheck:
+ ; If we've selected an architecture that doesn't have a download URL in the
+ ; partner.ini, but there is a URL there for 32-bit x86, then fall back to
+ ; 32-bit x86 on the theory that we should never use a non-partner build if
+ ; we are configured as a partner installer, even if the only build that's
+ ; provided is suboptimal for the machine. If there isn't even an x86 URL,
+ ; then we won't force x86 and GetDownloadURL will stick with the built-in URL.
+ ClearErrors
+ ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "X86"
+ ${IfNot} ${Errors}
+ ${If} $ArchToInstall == ${ARCH_AMD64}
+ ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AMD64"
+ ${If} ${Errors}
+ StrCpy $ArchToInstall ${ARCH_X86}
+ ${EndIf}
+ ${ElseIf} $ArchToInstall == ${ARCH_AARCH64}
+ ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AArch64"
+ ${If} ${Errors}
+ StrCpy $ArchToInstall ${ARCH_X86}
+ ${EndIf}
+ ${EndIf}
+ ${EndIf}
+FunctionEnd
+
+Function GetDownloadURL
+ Push $0
+ Push $1
+
+ ; Start with the appropriate URL from our built-in branding info.
+ ${If} $ArchToInstall == ${ARCH_AMD64}
+ StrCpy $0 "${URLStubDownloadAMD64}${URLStubDownloadAppend}"
+ ${ElseIf} $ArchToInstall == ${ARCH_AARCH64}
+ StrCpy $0 "${URLStubDownloadAArch64}${URLStubDownloadAppend}"
+ ${Else}
+ StrCpy $0 "${URLStubDownloadX86}${URLStubDownloadAppend}"
+ ${EndIf}
+
+ ; If we have a partner.ini file then use the URL from there instead.
+ ClearErrors
+ ${If} $ArchToInstall == ${ARCH_AMD64}
+ ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AMD64"
+ ${ElseIf} $ArchToInstall == ${ARCH_AARCH64}
+ ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AArch64"
+ ${Else}
+ ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "X86"
+ ${EndIf}
+ ${IfNot} ${Errors}
+ StrCpy $0 "$1"
+ ${EndIf}
+
+ Pop $1
+ Exch $0
+FunctionEnd
+
+Section
+SectionEnd
diff --git a/browser/installer/windows/nsis/uninstaller.nsi b/browser/installer/windows/nsis/uninstaller.nsi
new file mode 100755
index 0000000000..97b4ed11e8
--- /dev/null
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -0,0 +1,1133 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Required Plugins:
+# AppAssocReg
+# http://nsis.sourceforge.net/Application_Association_Registration_plug-in
+# BitsUtils
+# http://searchfox.org/mozilla-central/source/other-licenses/nsis/Contrib/BitsUtils
+# CityHash
+# http://searchfox.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
+# HttpPostFile
+# http://searchfox.org/mozilla-central/source/other-licenses/nsis/Contrib/HttpPostFile
+# ShellLink
+# http://nsis.sourceforge.net/ShellLink_plug-in
+# UAC
+# http://nsis.sourceforge.net/UAC_plug-in
+
+; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
+!verbose 3
+
+; 7-Zip provides better compression than the lzma from NSIS so we add the files
+; uncompressed and use 7-Zip to create a SFX archive of it
+SetDatablockOptimize on
+SetCompress off
+CRCCheck on
+
+RequestExecutionLevel user
+
+Unicode true
+ManifestSupportedOS all
+ManifestDPIAware true
+
+!addplugindir ./
+
+; Attempt to elevate Standard Users in addition to users that
+; are a member of the Administrators group.
+!define NONADMIN_ELEVATE
+
+; prevents compiling of the reg write logging.
+!define NO_LOG
+
+!define MaintUninstallKey \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\MozillaMaintenanceService"
+
+Var TmpVal
+Var MaintCertKey
+Var ShouldOpenSurvey
+Var ShouldSendPing
+Var InstalledVersion
+Var InstalledBuildID
+Var ShouldPromptForRefresh
+Var RefreshRequested
+; AddTaskbarSC is defined here in order to silence warnings from inside
+; MigrateTaskBarShortcut and is not intended to be used here.
+; See Bug 1329869 for more.
+Var AddTaskbarSC
+
+; Other included files may depend upon these includes!
+; The following includes are provided by NSIS.
+!include FileFunc.nsh
+!include InstallOptions.nsh
+!include LogicLib.nsh
+!include MUI.nsh
+!include WinMessages.nsh
+!include WinVer.nsh
+!include WordFunc.nsh
+
+!insertmacro GetSize
+!insertmacro StrFilter
+!insertmacro WordReplace
+
+!insertmacro un.GetParent
+
+; The following includes are custom.
+!include branding.nsi
+!include defines.nsi
+!include common.nsh
+!include locales.nsi
+
+; This is named BrandShortName helper because we use this for software update
+; post update cleanup.
+VIAddVersionKey "FileDescription" "${BrandShortName} Helper"
+VIAddVersionKey "OriginalFilename" "helper.exe"
+
+!insertmacro AddDisabledDDEHandlerValues
+!insertmacro CleanVirtualStore
+!insertmacro ElevateUAC
+!insertmacro GetLongPath
+!insertmacro GetPathFromString
+!insertmacro InitHashAppModelId
+!insertmacro IsHandlerForInstallDir
+!insertmacro IsPinnedToTaskBar
+!insertmacro IsUserAdmin
+!insertmacro LogDesktopShortcut
+!insertmacro LogQuickLaunchShortcut
+!insertmacro LogStartMenuShortcut
+!insertmacro PinnedToStartMenuLnkCount
+!insertmacro RegCleanAppHandler
+!insertmacro RegCleanMain
+!insertmacro RegCleanUninstall
+!insertmacro SetAppLSPCategories
+!insertmacro SetBrandNameVars
+!insertmacro UpdateShortcutAppModelIDs
+!insertmacro UnloadUAC
+!insertmacro WriteRegDWORD2
+!insertmacro WriteRegStr2
+
+; This needs to be inserted after InitHashAppModelId because it uses
+; $AppUserModelID and the compiler can't handle using variables lexically before
+; they've been declared.
+!insertmacro GetInstallerRegistryPref
+
+!insertmacro un.ChangeMUIHeaderImage
+!insertmacro un.ChangeMUISidebarImage
+!insertmacro un.CheckForFilesInUse
+!insertmacro un.CleanUpdateDirectories
+!insertmacro un.CleanVirtualStore
+!insertmacro un.DeleteShortcuts
+!insertmacro un.GetCommonDirectory
+!insertmacro un.GetLongPath
+!insertmacro un.GetSecondInstallPath
+!insertmacro un.InitHashAppModelId
+!insertmacro un.ManualCloseAppPrompt
+!insertmacro un.RegCleanAppHandler
+!insertmacro un.RegCleanFileHandler
+!insertmacro un.RegCleanMain
+!insertmacro un.RegCleanPrefs
+!insertmacro un.RegCleanUninstall
+!insertmacro un.RegCleanProtocolHandler
+!insertmacro un.RemoveQuotesFromPath
+!insertmacro un.RemovePrecompleteEntries
+!insertmacro un.SetAppLSPCategories
+!insertmacro un.SetBrandNameVars
+
+!include shared.nsh
+
+; Helper macros for ui callbacks. Insert these after shared.nsh
+!insertmacro OnEndCommon
+!insertmacro UninstallOnInitCommon
+
+!insertmacro un.OnEndCommon
+!insertmacro un.UninstallUnOnInitCommon
+
+Name "${BrandFullName}"
+OutFile "helper.exe"
+!ifdef HAVE_64BIT_BUILD
+ InstallDir "$PROGRAMFILES64\${BrandFullName}\"
+!else
+ InstallDir "$PROGRAMFILES32\${BrandFullName}\"
+!endif
+ShowUnInstDetails nevershow
+
+!define URLUninstallSurvey "https://qsurvey.mozilla.com/s3/FF-Desktop-Post-Uninstall?channel=${UpdateChannel}&version=${AppVersion}&osversion="
+
+; Support for the profile refresh feature
+!define URLProfileRefreshHelp "https://support.mozilla.org/kb/refresh-firefox-reset-add-ons-and-settings"
+
+; Arguments to add to the command line when launching FileMainEXE for profile refresh
+!define ArgsProfileRefresh "-reset-profile -migration -uninstaller-profile-refresh"
+
+################################################################################
+# Modern User Interface - MUI
+
+!define MUI_ABORTWARNING
+!define MUI_ICON setup.ico
+!define MUI_UNICON setup.ico
+!define MUI_WELCOMEPAGE_TITLE_3LINES
+!define MUI_HEADERIMAGE
+!define MUI_HEADERIMAGE_RIGHT
+!define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
+; By default MUI_BGCOLOR is hardcoded to FFFFFF, which is only correct if the
+; the Windows theme or high-contrast mode hasn't changed it, so we need to
+; override that with GetSysColor(COLOR_WINDOW) (this string ends up getting
+; passed to SetCtlColors, which uses this custom syntax to mean that).
+!define MUI_BGCOLOR SYSCLR:WINDOW
+
+; Use a right to left header image when the language is right to left
+!ifdef ${AB_CD}_rtl
+!define MUI_HEADERIMAGE_BITMAP_RTL wizHeaderRTL.bmp
+!else
+!define MUI_HEADERIMAGE_BITMAP wizHeader.bmp
+!endif
+
+!define MUI_CUSTOMFUNCTION_UNGUIINIT un.GUIInit
+
+/**
+ * Uninstall Pages
+ */
+; Welcome Page
+!define MUI_PAGE_CUSTOMFUNCTION_PRE un.preWelcome
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW un.showWelcome
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.leaveWelcome
+!insertmacro MUI_UNPAGE_WELCOME
+
+; Custom Uninstall Confirm Page
+UninstPage custom un.preConfirm
+
+; Remove Files Page
+!insertmacro MUI_UNPAGE_INSTFILES
+
+; Finish Page
+!define MUI_FINISHPAGE_SHOWREADME
+!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
+!define MUI_FINISHPAGE_SHOWREADME_TEXT $(UN_SURVEY_CHECKBOX_LABEL)
+!define MUI_FINISHPAGE_SHOWREADME_FUNCTION un.Survey
+!define MUI_PAGE_CUSTOMFUNCTION_PRE un.preFinish
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW un.showFinish
+!insertmacro MUI_UNPAGE_FINISH
+
+; Use the default dialog for IDD_VERIFY for a simple Banner
+ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe"
+
+################################################################################
+# Helper Functions
+
+Function un.Survey
+ ; We can't actually call ExecInExplorer here because it's going to have to
+ ; make some marshalled COM calls and those are not allowed from within a
+ ; synchronous message handler (where we currently are); we'll be thrown
+ ; RPC_E_CANTCALLOUT_ININPUTSYNCCALL if we try. So all we can do is record
+ ; that we need to make the call later, which we'll do from un.onGUIEnd.
+ StrCpy $ShouldOpenSurvey "1"
+FunctionEnd
+
+; This function is used to uninstall the maintenance service if the
+; application currently being uninstalled is the last application to use the
+; maintenance service.
+Function un.UninstallServiceIfNotUsed
+ ; $0 will store if a subkey exists
+ ; $1 will store the first subkey if it exists or an empty string if it doesn't
+ ; Backup the old values
+ Push $0
+ Push $1
+
+ ; The maintenance service always uses the 64-bit registry on x64 systems
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView 64
+ ${EndIf}
+
+ ; Figure out the number of subkeys
+ StrCpy $0 0
+ ${Do}
+ EnumRegKey $1 HKLM "Software\Mozilla\MaintenanceService" $0
+ ${If} "$1" == ""
+ ${ExitDo}
+ ${EndIf}
+ IntOp $0 $0 + 1
+ ${Loop}
+
+ ; Restore back the registry view
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView lastused
+ ${EndIf}
+
+ ${If} $0 == 0
+ ; Get the path of the maintenance service uninstaller.
+ ; Look in both the 32-bit and 64-bit registry views.
+ SetRegView 32
+ ReadRegStr $1 HKLM ${MaintUninstallKey} "UninstallString"
+ SetRegView lastused
+
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ ${If} $1 == ""
+ SetRegView 64
+ ReadRegStr $1 HKLM ${MaintUninstallKey} "UninstallString"
+ SetRegView lastused
+ ${EndIf}
+ ${EndIf}
+
+ ; If the uninstall string does not exist, skip executing it
+ ${If} $1 != ""
+ ; $1 is already a quoted string pointing to the install path
+ ; so we're already protected against paths with spaces
+ nsExec::Exec "$1 /S"
+ ${EndIf}
+ ${EndIf}
+
+ ; Restore the old value of $1 and $0
+ Pop $1
+ Pop $0
+FunctionEnd
+
+Function un.LaunchAppForRefresh
+ Push $0
+ Push $1
+ ; Set the current working directory to the installation directory
+ SetOutPath "$INSTDIR"
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $1
+ ${If} ${Errors}
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" ${ArgsProfileRefresh}"
+ ${Else}
+ GetFunctionAddress $0 un.LaunchAppForRefreshFromElevatedProcess
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+ Pop $1
+ Pop $0
+FunctionEnd
+
+Function un.LaunchAppForRefreshFromElevatedProcess
+ ; Set the current working directory to the installation directory
+ SetOutPath "$INSTDIR"
+ ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" ${ArgsProfileRefresh}"
+FunctionEnd
+
+Function un.LaunchRefreshHelpPage
+ Push $0
+ Push $1
+ ClearErrors
+ ${GetParameters} $0
+ ${GetOptions} "$0" "/UAC:" $1
+ ${If} ${Errors}
+ Call un.OpenRefreshHelpURL
+ ${Else}
+ GetFunctionAddress $0 un.OpenRefreshHelpURL
+ UAC::ExecCodeSegment $0
+ ${EndIf}
+ Pop $1
+ Pop $0
+FunctionEnd
+
+Function un.OpenRefreshHelpURL
+ ExecShell "open" "${URLProfileRefreshHelp}"
+FunctionEnd
+
+Function un.SendUninstallPing
+ ; Notably, we only check the non-private AUMID here. There's no good reason
+ ; to send the uninstall ping twice.
+ ${If} $AppUserModelID == ""
+ Return
+ ${EndIf}
+
+ Push $0 ; $0 = Find handle
+ Push $1 ; $1 = Found ping file name
+ Push $2 ; $2 = Directory containing the pings
+ Push $3 ; $3 = Ping file name filespec
+ Push $4 ; $4 = Offset of ID in file name
+ Push $5 ; $5 = URL, POST result
+ Push $6 ; $6 = Full path to the ping file
+
+ Call un.GetCommonDirectory
+ Pop $2
+
+ ; The ping ID is in the file name, so that we can get it for the submission URL
+ ; without having to parse the ping. Since we don't know the exact name, use FindFirst
+ ; to locate the file.
+ ; Format is uninstall_ping_$AppUserModelID_$PingUUID.json
+
+ ; File name base
+ StrCpy $3 "uninstall_ping_$AppUserModelID_"
+ ; Get length of the fixed prefix, this is the offset of ping ID in the file name
+ StrLen $4 $3
+ ; Finish building filespec
+ StrCpy $3 "$2\$3*.json"
+
+ ClearErrors
+ FindFirst $0 $1 $3
+ ; Build the full path
+ StrCpy $6 "$2\$1"
+
+ ${IfNot} ${Errors}
+ ; Copy the ping ID, starting after $AppUserModelID_, ending 5 from the end to remove .json
+ StrCpy $5 $1 -5 $4
+
+ ; Build the full submission URL from the ID
+ ; https://docs.telemetry.mozilla.org/concepts/pipeline/http_edge_spec.html#special-handling-for-firefox-desktop-telemetry
+ ; It's possible for the path components to disagree with the contents of the ping,
+ ; but this should be rare, and shouldn't affect the collection.
+ StrCpy $5 "${TELEMETRY_BASE_URL}/${TELEMETRY_UNINSTALL_PING_NAMESPACE}/$5/${TELEMETRY_UNINSTALL_PING_DOCTYPE}/${AppName}/$InstalledVersion/${UpdateChannel}/$InstalledBuildID?v=4"
+
+ HttpPostFile::Post $6 "Content-Type: application/json$\r$\n" $5
+ ; Pop the result. This could indicate an error if it's something other than
+ ; "success", but we don't have any recovery path here anyway.
+ Pop $5
+
+ ${Do}
+ Delete $6
+
+ ; Continue to delete any other pings from this install. Only the first found will be sent:
+ ; there should only be one ping, if there are more than one then something has gone wrong,
+ ; it seems preferable to not try to send them all.
+ ClearErrors
+ FindNext $0 $1
+ ; Build the full path
+ StrCpy $6 "$2\$1"
+ ${LoopUntil} ${Errors}
+
+ FindClose $0
+ ${Endif}
+
+ Pop $6
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+
+################################################################################
+# Install Sections
+; Empty section required for the installer to compile as an uninstaller
+Section ""
+SectionEnd
+
+################################################################################
+# Uninstall Sections
+
+Section "Uninstall"
+ SetDetailsPrint textonly
+ DetailPrint $(STATUS_UNINSTALL_MAIN)
+ SetDetailsPrint none
+
+ ; Some system cleanup is most easily handled when XPCOM functionality is
+ ; available - e.g. removing notifications from Window's Action Center. We
+ ; handle this in the `uninstall` background task.
+ ;
+ ; Return value is saved to an unused variable to prevent the the error flag
+ ; from being set.
+ Var /GLOBAL UnusedExecCatchReturn
+ ExecWait '"$INSTDIR\${FileMainEXE}" --backgroundtask uninstall' $UnusedExecCatchReturn
+
+ ; Delete the app exe to prevent launching the app while we are uninstalling.
+ ClearErrors
+ ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+ ${If} ${Errors}
+ ; If the user closed the application it can take several seconds for it to
+ ; shut down completely. If the application is being used by another user we
+ ; can still delete the files when the system is restarted.
+ Sleep 5000
+ ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+ ClearErrors
+ ${EndIf}
+
+ SetShellVarContext current ; Set SHCTX to HKCU
+ ${un.RegCleanMain} "Software\Mozilla"
+ ${un.RegCleanPrefs} "Software\Mozilla\${AppName}"
+ ${un.RegCleanUninstall}
+ ${un.DeleteShortcuts}
+
+ ${If} "$AppUserModelID" != ""
+ ; Unregister resources associated with Win7 taskbar jump lists.
+ ${If} ${AtLeastWin7}
+ ApplicationID::UninstallJumpLists "$AppUserModelID"
+ ${EndIf}
+ ; Remove the update sync manager's multi-instance lock file
+ Call un.GetCommonDirectory
+ Pop $0
+ Delete /REBOOTOK "$0\UpdateLock-$AppUserModelID"
+ ${EndIf}
+
+ ${If} "$AppUserModelIDPrivate" != ""
+ ${If} ${AtLeastWin7}
+ ApplicationID::UninstallJumpLists "$AppUserModelIDPrivate"
+ ${EndIf}
+ ${EndIf}
+
+ ; Remove the updates directory
+ ${un.CleanUpdateDirectories} "Mozilla\Firefox" "Mozilla\updates"
+
+ ; Remove any app model id's stored in the registry for this install path
+ DeleteRegValue HKCU "Software\Mozilla\${AppName}\TaskBarIDs" "$INSTDIR"
+ DeleteRegValue HKLM "Software\Mozilla\${AppName}\TaskBarIDs" "$INSTDIR"
+
+ ClearErrors
+ WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
+ ${If} ${Errors}
+ StrCpy $TmpVal "HKCU" ; used primarily for logging
+ ${Else}
+ SetShellVarContext all ; Set SHCTX to HKLM
+ DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+ StrCpy $TmpVal "HKLM" ; used primarily for logging
+ ${un.RegCleanMain} "Software\Mozilla"
+ ${un.RegCleanUninstall}
+ ${un.DeleteShortcuts}
+ ${un.SetAppLSPCategories}
+ ${EndIf}
+
+ ${un.RegCleanAppHandler} "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanAppHandler} "FirefoxPDF-$AppUserModelID"
+ ${un.RegCleanAppHandler} "FirefoxURL-$AppUserModelID"
+ ${un.RegCleanProtocolHandler} "http"
+ ${un.RegCleanProtocolHandler} "https"
+ ${un.RegCleanProtocolHandler} "mailto"
+ ${un.RegCleanFileHandler} ".htm" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".html" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".shtml" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".xht" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".xhtml" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".oga" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".ogg" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".ogv" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".webm" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".svg" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".webp" "FirefoxHTML-$AppUserModelID"
+ ${un.RegCleanFileHandler} ".avif" "FirefoxHTML-$AppUserModelID"
+
+ ${un.RegCleanFileHandler} ".pdf" "FirefoxPDF-$AppUserModelID"
+
+ SetShellVarContext all ; Set SHCTX to HKLM
+ ${un.GetSecondInstallPath} "Software\Mozilla" $R9
+ ${If} $R9 == "false"
+ SetShellVarContext current ; Set SHCTX to HKCU
+ ${un.GetSecondInstallPath} "Software\Mozilla" $R9
+ ${EndIf}
+
+ DeleteRegKey HKLM "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID"
+ DeleteRegValue HKLM "Software\RegisteredApplications" "${AppRegName}-$AppUserModelID"
+
+ DeleteRegKey HKCU "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID"
+ DeleteRegValue HKCU "Software\RegisteredApplications" "${AppRegName}-$AppUserModelID"
+
+ ; Remove old protocol handler and StartMenuInternet keys without install path
+ ; hashes, but only if they're for this installation. We've never supported
+ ; bare FirefoxPDF.
+ ReadRegStr $0 HKLM "Software\Classes\FirefoxHTML\DefaultIcon" ""
+ StrCpy $0 $0 -2
+ ${If} $0 == "$INSTDIR\${FileMainEXE}"
+ DeleteRegKey HKLM "Software\Classes\FirefoxHTML"
+ DeleteRegKey HKLM "Software\Classes\FirefoxURL"
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
+ DeleteRegKey HKLM "Software\Clients\StartMenuInternet\$R9"
+ DeleteRegValue HKLM "Software\RegisteredApplications" "$R9"
+ DeleteRegValue HKLM "Software\RegisteredApplications" "${AppRegName}"
+ ${EndIf}
+ ReadRegStr $0 HKCU "Software\Classes\FirefoxHTML\DefaultIcon" ""
+ StrCpy $0 $0 -2
+ ${If} $0 == "$INSTDIR\${FileMainEXE}"
+ DeleteRegKey HKCU "Software\Classes\FirefoxHTML"
+ DeleteRegKey HKCU "Software\Classes\FirefoxURL"
+ ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
+ DeleteRegKey HKCU "Software\Clients\StartMenuInternet\$R9"
+ DeleteRegValue HKCU "Software\RegisteredApplications" "$R9"
+ DeleteRegValue HKCU "Software\RegisteredApplications" "${AppRegName}"
+ ${EndIf}
+
+ StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}"
+ ${If} $R9 == "false"
+ DeleteRegKey HKLM "$0"
+ DeleteRegKey HKCU "$0"
+ StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\${FileMainEXE}"
+ DeleteRegKey HKLM "$0"
+ DeleteRegKey HKCU "$0"
+ StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\plugin-container.exe"
+ DeleteRegKey HKLM "$0"
+ DeleteRegKey HKCU "$0"
+ StrCpy $0 "Software\Classes\MIME\Database\Content Type\application/x-xpinstall;app=firefox"
+ DeleteRegKey HKLM "$0"
+ DeleteRegKey HKCU "$0"
+ ${Else}
+ ReadRegStr $R1 HKLM "$0" ""
+ ${un.RemoveQuotesFromPath} "$R1" $R1
+ ${un.GetParent} "$R1" $R1
+ ${If} "$INSTDIR" == "$R1"
+ WriteRegStr HKLM "$0" "" "$R9"
+ ${un.GetParent} "$R9" $R1
+ WriteRegStr HKLM "$0" "Path" "$R1"
+ ${EndIf}
+ ${EndIf}
+
+ ; Remove our HKCR/Applications key, if it's for this installation.
+ ReadRegStr $0 HKLM "Software\Classes\Applications\${FileMainEXE}\DefaultIcon" ""
+ StrCpy $0 $0 -2
+ ${If} $0 == "$INSTDIR\${FileMainEXE}"
+ DeleteRegKey HKLM "Software\Classes\Applications\${FileMainEXE}"
+ ${EndIf}
+ ReadRegStr $0 HKCU "Software\Classes\Applications\${FileMainEXE}\DefaultIcon" ""
+ StrCpy $0 $0 -2
+ ${If} $0 == "$INSTDIR\${FileMainEXE}"
+ DeleteRegKey HKCU "Software\Classes\Applications\${FileMainEXE}"
+ ${EndIf}
+
+ ; Remove directories and files we always control before parsing the uninstall
+ ; log so empty directories can be removed.
+ ${If} ${FileExists} "$INSTDIR\updates"
+ RmDir /r /REBOOTOK "$INSTDIR\updates"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\updated"
+ RmDir /r /REBOOTOK "$INSTDIR\updated"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\defaults\shortcuts"
+ RmDir /r /REBOOTOK "$INSTDIR\defaults\shortcuts"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\distribution"
+ RmDir /r /REBOOTOK "$INSTDIR\distribution"
+ ${EndIf}
+
+ ; Remove files that may be left behind by the application in the
+ ; VirtualStore directory.
+ ${un.CleanVirtualStore}
+
+ ; Only unregister the dll if the registration points to this installation
+ ReadRegStr $R1 HKCR "CLSID\{0D68D6D0-D93D-4D08-A30D-F00DD1F45B24}\InProcServer32" ""
+ ${If} "$INSTDIR\AccessibleMarshal.dll" == "$R1"
+ ${UnregisterDLL} "$INSTDIR\AccessibleMarshal.dll"
+ ${EndIf}
+
+ ; Only unregister the dll if the registration points to this installation
+ ReadRegStr $R1 HKCR "CLSID\${AccessibleHandlerCLSID}\InprocHandler32" ""
+ ${If} "$INSTDIR\AccessibleHandler.dll" == "$R1"
+ ${UnregisterDLL} "$INSTDIR\AccessibleHandler.dll"
+ ${EndIf}
+
+ ; Remove the Windows Reporter Module entry
+ DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\RuntimeExceptionHelperModules" "$INSTDIR\mozwer.dll"
+
+!ifdef MOZ_LAUNCHER_PROCESS
+ DeleteRegValue HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Launcher"
+ DeleteRegValue HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Browser"
+ DeleteRegValue HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Image"
+ DeleteRegValue HKCU ${MOZ_LAUNCHER_SUBKEY} "$INSTDIR\${FileMainEXE}|Telemetry"
+!endif
+
+ ; Remove Toast Notification registration.
+ ${If} ${AtLeastWin10}
+ ; Find any GUID used for this installation.
+ ClearErrors
+ ReadRegStr $0 HKLM "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "CustomActivator"
+
+ DeleteRegValue HKLM "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "CustomActivator"
+ DeleteRegValue HKLM "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "DisplayName"
+ DeleteRegValue HKLM "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "IconUri"
+ DeleteRegKey HKLM "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID"
+ ${If} "$0" != ""
+ DeleteRegValue HKLM "Software\Classes\AppID\$0" "DllSurrogate"
+ DeleteRegKey HKLM "Software\Classes\AppID\$0"
+ DeleteRegValue HKLM "Software\Classes\CLSID\$0" "AppID"
+ DeleteRegValue HKLM "Software\Classes\CLSID\$0\InProcServer32" ""
+ DeleteRegKey HKLM "Software\Classes\CLSID\$0\InProcServer32"
+ DeleteRegKey HKLM "Software\Classes\CLSID\$0"
+ ${EndIf}
+
+ ClearErrors
+ ReadRegStr $0 HKCU "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "CustomActivator"
+
+ DeleteRegValue HKCU "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "CustomActivator"
+ DeleteRegValue HKCU "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "DisplayName"
+ DeleteRegValue HKCU "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID" "IconUri"
+ DeleteRegKey HKCU "Software\Classes\AppUserModelId\${ToastAumidPrefix}$AppUserModelID"
+ ${If} "$0" != ""
+ DeleteRegValue HKCU "Software\Classes\AppID\$0" "DllSurrogate"
+ DeleteRegKey HKCU "Software\Classes\AppID\$0"
+ DeleteRegValue HKCU "Software\Classes\CLSID\$0" "AppID"
+ DeleteRegValue HKCU "Software\Classes\CLSID\$0\InProcServer32" ""
+ DeleteRegKey HKCU "Software\Classes\CLSID\$0\InProcServer32"
+ DeleteRegKey HKCU "Software\Classes\CLSID\$0"
+ ${EndIf}
+ ${EndIf}
+
+ ; Uninstall the default browser agent scheduled task and all other scheduled
+ ; tasks registered by Firefox.
+ ; This also removes the registry entries that the WDBA creates.
+ ; One of the scheduled tasks that this will remove is the Background Update
+ ; Task. Ideally, this will eventually be changed so that it doesn't rely on
+ ; the WDBA. See Bug 1710143.
+ ExecWait '"$INSTDIR\default-browser-agent.exe" uninstall $AppUserModelID'
+ ${RemoveDefaultBrowserAgentShortcut}
+
+ ${un.RemovePrecompleteEntries} "false"
+
+ ${If} ${FileExists} "$INSTDIR\defaults\pref\channel-prefs.js"
+ Delete /REBOOTOK "$INSTDIR\defaults\pref\channel-prefs.js"
+ ${EndIf}
+ RmDir "$INSTDIR\defaults\pref"
+ RmDir "$INSTDIR\defaults"
+ ${If} ${FileExists} "$INSTDIR\uninstall"
+ ; Remove the uninstall directory that we control
+ RmDir /r /REBOOTOK "$INSTDIR\uninstall"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\install.log"
+ Delete /REBOOTOK "$INSTDIR\install.log"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\update-settings.ini"
+ Delete /REBOOTOK "$INSTDIR\update-settings.ini"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\installation_telemetry.json"
+ Delete /REBOOTOK "$INSTDIR\installation_telemetry.json"
+ ${EndIf}
+ ${If} ${FileExists} "$INSTDIR\postSigningData"
+ Delete /REBOOTOK "$INSTDIR\postSigningData"
+ ${EndIf}
+
+ ; Explicitly remove empty webapprt dir in case it exists (bug 757978).
+ RmDir "$INSTDIR\webapprt\components"
+ RmDir "$INSTDIR\webapprt"
+
+ ; Remove the installation directory if it is empty
+ RmDir "$INSTDIR"
+
+ ; If firefox.exe was successfully deleted yet we still need to restart to
+ ; remove other files create a dummy firefox.exe.moz-delete to prevent the
+ ; installer from allowing an install without restart when it is required
+ ; to complete an uninstall.
+ ${If} ${RebootFlag}
+ ; Admin is required to delete files on reboot so only add the moz-delete if
+ ; the user is an admin. After calling UAC::IsAdmin $0 will equal 1 if the
+ ; user is an admin.
+ UAC::IsAdmin
+ ${If} "$0" == "1"
+ ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-delete"
+ FileOpen $0 "$INSTDIR\${FileMainEXE}.moz-delete" w
+ FileWrite $0 "Will be deleted on restart"
+ Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete"
+ FileClose $0
+ ${EndUnless}
+ ${EndIf}
+ ${EndIf}
+
+ ; Refresh desktop icons otherwise the start menu internet item won't be
+ ; removed and other ugly things will happen like recreation of the app's
+ ; clients registry key by the OS under some conditions.
+ ${RefreshShellIcons}
+
+ ; Users who uninstall then reinstall expecting Firefox to use a clean profile
+ ; may be surprised during first-run. This key is checked during startup of Firefox and
+ ; subsequently deleted after checking. If the value is found during startup
+ ; the browser will offer to Reset Firefox. We use the UpdateChannel to match
+ ; uninstalls of Firefox-release with reinstalls of Firefox-release, for example.
+ WriteRegStr HKCU "Software\Mozilla\Firefox" "Uninstalled-${UpdateChannel}" "True"
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+ ; Get the path the allowed cert is at and remove it
+ ; Keep this block of code last since it modfies the reg view
+ ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
+ Pop $MaintCertKey
+ ${If} $MaintCertKey != ""
+ ; Always use the 64bit registry for certs on 64bit systems.
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView 64
+ ${EndIf}
+ DeleteRegKey HKLM "$MaintCertKey"
+ ${If} ${RunningX64}
+ ${OrIf} ${IsNativeARM64}
+ SetRegView lastused
+ ${EndIf}
+ ${EndIf}
+ Call un.UninstallServiceIfNotUsed
+!endif
+
+!ifdef MOZ_BITS_DOWNLOAD
+ BitsUtils::CancelBitsJobsByName "MozillaUpdate $AppUserModelID"
+ Pop $0
+!endif
+
+ ${un.IsFirewallSvcRunning}
+ Pop $0
+ ${If} "$0" == "true"
+ liteFirewallW::RemoveRule "$INSTDIR\${FileMainEXE}" "${BrandShortName} ($INSTDIR)"
+ ${EndIf}
+SectionEnd
+
+################################################################################
+# Language
+
+!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
+!verbose push
+!verbose 3
+!include "overrideLocale.nsh"
+!include "customLocale.nsh"
+!verbose pop
+
+; Set this after the locale files to override it if it is in the locale. Using
+; " " for BrandingText will hide the "Nullsoft Install System..." branding.
+BrandingText " "
+
+################################################################################
+# Page pre, show, and leave functions
+
+Function un.preWelcome
+ ${If} ${FileExists} "$INSTDIR\distribution\modern-wizard.bmp"
+ Delete "$PLUGINSDIR\modern-wizard.bmp"
+ CopyFiles /SILENT "$INSTDIR\distribution\modern-wizard.bmp" "$PLUGINSDIR\modern-wizard.bmp"
+ ${EndIf}
+!ifdef MOZ_BITS_DOWNLOAD
+ BitsUtils::StartBitsServiceBackground
+!endif
+
+ ; We don't want the header bitmap showing on the welcome page.
+ GetDlgItem $0 $HWNDPARENT 1046
+ ShowWindow $0 ${SW_HIDE}
+
+ ${If} $ShouldPromptForRefresh == "1"
+ ; Note: INI strings added here (rather than overwriting an existing value)
+ ; should be removed in un.leaveWelcome, since ioSpecial.ini is reused
+ ; for the Finish page.
+
+ ; Replace title and body text
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 2" Text "$(UN_REFRESH_PAGE_TITLE)"
+ ; Convert to translate newlines, this includes $PLUGINSDIR internally.
+ !insertmacro INSTALLOPTIONS_WRITE_UNCONVERT "ioSpecial.ini" "Field 3" Text "$(UN_REFRESH_PAGE_EXPLANATION)"
+
+ ; Make room for the link and button
+ StrCpy $0 "148"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 3" Bottom $0
+
+ ; Show the help link
+ IntOp $1 $0 + 14
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Type "link"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Text "$(UN_REFRESH_LEARN_MORE)"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Left "120"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Top $0
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Right "315"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Bottom $1
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Flags "NOTIFY"
+
+ ; Show the refresh button.
+ IntOp $2 $1 + 14
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Type "button"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Text "$(UN_REFRESH_BUTTON)"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Left "120"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Top $1
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Right "240"
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Bottom $2
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 5" Flags "NOTIFY"
+
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Settings" NumFields 5
+ ${EndIf}
+FunctionEnd
+
+Function un.ShowWelcome
+ ; The welcome and finish pages don't get the correct colors for their labels
+ ; like the other pages do, presumably because they're built by filling in an
+ ; InstallOptions .ini file instead of from a dialog resource like the others.
+ ; Field 2 is the header and Field 3 is the body text.
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 2" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 3" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ${If} $ShouldPromptForRefresh == "1"
+ ; Field 4 is the profile refresh help link
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 4" "HWND"
+ SetCtlColors $0 SYSCLR:HOTLIGHT SYSCLR:WINDOW
+ ${EndIf}
+
+ ; We need to overwrite the sidebar image so that we get it drawn with proper
+ ; scaling if the display is scaled at anything above 100%.
+ ${un.ChangeMUISidebarImage} "$PLUGINSDIR\modern-wizard.bmp"
+FunctionEnd
+
+Function un.leaveWelcome
+ StrCpy $RefreshRequested "0"
+
+ ${If} $ShouldPromptForRefresh == "1"
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Settings" "State"
+ ${If} $0 == "5"
+ ; Refresh button
+ StrCpy $RefreshRequested "1"
+ ${ElseIf} $0 == "4"
+ ; Launch refresh help link, stay on this page
+ Call un.LaunchRefreshHelpPage
+ Abort
+ ${EndIf}
+ ${EndIf}
+
+ ${If} ${FileExists} "$INSTDIR\${FileMainEXE}"
+ Banner::show /NOUNLOAD "$(BANNER_CHECK_EXISTING)"
+
+ ; If we already found a window once and we're checking again, wait for an
+ ; additional five seconds for the app to close.
+ ${If} "$TmpVal" == "FoundAppWindow"
+ Sleep 5000
+ ${EndIf}
+
+ ${PushFilesToCheck}
+
+ ${un.CheckForFilesInUse} $TmpVal
+
+ Banner::destroy
+
+ ; If there are files in use $TmpVal will be "true"
+ ${If} "$TmpVal" == "true"
+ ; If it finds a window of the right class, then ManualCloseAppPrompt will
+ ; abort leaving the value of $TmpVal set to "FoundAppWindow".
+ StrCpy $TmpVal "FoundAppWindow"
+
+ ${If} $RefreshRequested == "1"
+ ${un.ManualCloseAppPrompt} "${MainWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_REFRESH)"
+ ${un.ManualCloseAppPrompt} "${DialogWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_REFRESH)"
+ ${Else}
+ ${un.ManualCloseAppPrompt} "${MainWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_UNINSTALL)"
+ ${un.ManualCloseAppPrompt} "${DialogWindowClass}" "$(WARN_MANUALLY_CLOSE_APP_UNINSTALL)"
+ ${EndIf}
+ ; If the message window is not found set $TmpVal to "true" so the restart
+ ; required message is displayed.
+ ; In the case of a refresh request the restart required message will not be displayed;
+ ; we're not trying to change the installation, so files in use only matter if the
+ ; window is shown.
+ StrCpy $TmpVal "true"
+ ${EndIf}
+ ${EndIf}
+
+ ${If} $RefreshRequested == "1"
+ Call un.LaunchAppForRefresh
+ Quit
+ ${EndIf}
+
+ ${If} $ShouldPromptForRefresh == "1"
+ ; Remove the custom controls.
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Settings" NumFields 3
+ DeleteIniSec "$PLUGINSDIR\ioSpecial.ini" "Field 4"
+ DeleteIniSec "$PLUGINSDIR\ioSpecial.ini" "Field 5"
+ ${EndIf}
+
+ ; Bring back the header bitmap for the next pages.
+ GetDlgItem $0 $HWNDPARENT 1046
+ ShowWindow $0 ${SW_SHOW}
+FunctionEnd
+
+Function un.preConfirm
+ ; The header on the wizard pages doesn't get the correct text
+ ; color by default for some reason, even though the other controls do.
+ GetDlgItem $0 $HWNDPARENT 1037
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+ ; Hide unused subheader (to avoid overlapping moved header)
+ GetDlgItem $0 $HWNDPARENT 1038
+ ShowWindow $0 ${SW_HIDE}
+
+ ${If} ${FileExists} "$INSTDIR\distribution\modern-header.bmp"
+ Delete "$PLUGINSDIR\modern-header.bmp"
+ CopyFiles /SILENT "$INSTDIR\distribution\modern-header.bmp" "$PLUGINSDIR\modern-header.bmp"
+ ${EndIf}
+ ${un.ChangeMUIHeaderImage} "$PLUGINSDIR\modern-header.bmp"
+
+ ; Setup the unconfirm.ini file for the Custom Uninstall Confirm Page
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "3"
+
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Type "label"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Text "$(UN_CONFIRM_UNINSTALLED_FROM)"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Left "0"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Right "-1"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Top "5"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Bottom "15"
+
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Type "text"
+ ; The contents of this control must be set as follows in the pre function
+ ; ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 2" "HWND"
+ ; SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" State ""
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Left "0"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Right "-1"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Top "17"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Bottom "30"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" flags "READONLY"
+
+ ${If} "$TmpVal" == "true"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Type "label"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Text "$(SUMMARY_REBOOT_REQUIRED_UNINSTALL)"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Left "0"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Right "-1"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "35"
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "45"
+
+ WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "3"
+ ${EndIf}
+
+ !insertmacro MUI_HEADER_TEXT "$(UN_CONFIRM_PAGE_TITLE)" ""
+
+ ; The Summary custom page has a textbox that will automatically receive
+ ; focus. This sets the focus to the Install button instead.
+ !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "unconfirm.ini"
+ GetDlgItem $0 $HWNDPARENT 1
+ System::Call "user32::SetFocus(i r0, i 0x0007, i,i)i"
+ ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 2" "HWND"
+ SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR"
+ !insertmacro MUI_INSTALLOPTIONS_SHOW
+FunctionEnd
+
+Function un.onUninstSuccess
+ ; Send a ping at un.onGUIEnd, to avoid freezing the GUI.
+ StrCpy $ShouldSendPing "1"
+
+ ${If} ${Silent}
+ ; If this is a silent uninstall then un.onGUIEnd doesn't run, so do it now.
+ Call un.SendUninstallPing
+ ${EndIf}
+FunctionEnd
+
+Function un.preFinish
+ ; Need to give the survey (readme) checkbox a few extra DU's of height
+ ; to accommodate a potentially multi-line label. If the reboot flag is set,
+ ; then we're not showing the survey checkbox and Field 4 is the "reboot now"
+ ; radio button; setting it to go from 90 to 120 (instead of 90 to 100) would
+ ; cover up Field 5 which is "reboot later", running from 110 to 120. For
+ ; whatever reason child windows get created at the bottom of the z-order, so
+ ; 4 overlaps 5.
+ ${IfNot} ${RebootFlag}
+ WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Bottom "120"
+ ${EndIf}
+
+ ; We don't want the header bitmap showing on the finish page.
+ GetDlgItem $0 $HWNDPARENT 1046
+ ShowWindow $0 ${SW_HIDE}
+FunctionEnd
+
+Function un.ShowFinish
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 2" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 3" "HWND"
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ; We need to overwrite the sidebar image so that we get it drawn with proper
+ ; scaling if the display is scaled at anything above 100%.
+ ${un.ChangeMUISidebarImage} "$PLUGINSDIR\modern-wizard.bmp"
+
+ ; Either Fields 4 and 5 are the reboot option radio buttons, or Field 4 is
+ ; the survey checkbox and Field 5 doesn't exist. Either way, we need to
+ ; clear the theme from them before we can set their background colors.
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 4" "HWND"
+ System::Call 'uxtheme::SetWindowTheme(i $0, w " ", w " ")'
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+
+ ClearErrors
+ ReadINIStr $0 "$PLUGINSDIR\ioSpecial.ini" "Field 5" "HWND"
+ ${IfNot} ${Errors}
+ System::Call 'uxtheme::SetWindowTheme(i $0, w " ", w " ")'
+ SetCtlColors $0 SYSCLR:WINDOWTEXT SYSCLR:WINDOW
+ ${EndIf}
+FunctionEnd
+
+################################################################################
+# Initialization Functions
+
+Function .onInit
+ ; Remove the current exe directory from the search order.
+ ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
+ System::Call 'kernel32::SetDllDirectoryW(w "")'
+
+ ; We need this set up for most of the helper.exe operations.
+ ${UninstallOnInitCommon}
+FunctionEnd
+
+Function un.onInit
+ ; Remove the current exe directory from the search order.
+ ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
+ System::Call 'kernel32::SetDllDirectoryW(w "")'
+
+ StrCpy $LANGUAGE 0
+ StrCpy $ShouldOpenSurvey "0"
+
+ ${un.UninstallUnOnInitCommon}
+
+ ; setup the application model id registration value
+ ${un.InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
+
+ ; Find a default profile for this install.
+ SetShellVarContext current
+ ${un.FindInstallSpecificProfile}
+ Pop $1
+ GetFullPathName $1 $1
+
+ ; If there is an existing default profile, offer profile refresh.
+ StrCpy $ShouldPromptForRefresh "0"
+ StrCpy $RefreshRequested "0"
+ ${If} $1 != ""
+ StrCpy $ShouldPromptForRefresh "1"
+ ${EndIf}
+
+ ; Load version info for uninstall ping (sent after uninstall is complete)
+ ReadINIStr $InstalledVersion "$INSTDIR\application.ini" "App" "Version"
+ ReadINIStr $InstalledBuildID "$INSTDIR\application.ini" "App" "BuildID"
+
+ !insertmacro InitInstallOptionsFile "unconfirm.ini"
+FunctionEnd
+
+Function un.GUIInit
+ ; Move header text down, roughly vertically centered in the header.
+ ; Even if we're not changing the X, we can't set Y without also setting X.
+ ; Child window positions have to be set in client coordinates, and these are
+ ; left-to-right mirrored for RTL.
+ GetDlgItem $0 $HWNDPARENT 1037
+ ; Get current rect in screen coordinates
+ System::Call "*(i 0, i 0, i 0, i 0) i .r2"
+ System::Call "user32::GetWindowRect(p $0, p $2)"
+ ; Convert screen coordinates to client coordinates (handles RTL mirroring)
+ System::Call "user32::MapWindowPoints(p 0, p $HWNDPARENT, p $2, i 2)"
+ System::Call "*$2(i . r3, i . r4, i, i)"
+ System::Free $2
+ ; Move down
+ ${DialogUnitsToPixels} 8 Y $1
+ IntOp $4 $4 + $1
+ ; Set position, 0x0015 is SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE
+ System::Call "user32::SetWindowPos(p $0, p 0, i $3, i $4, i 0, i 0, i 0x0015)"
+FunctionEnd
+
+Function .onGUIEnd
+ ${OnEndCommon}
+FunctionEnd
+
+Function un.onGUIEnd
+ ${un.OnEndCommon}
+
+ ${If} $ShouldOpenSurvey == "1"
+ ; Though these values are sometimes incorrect due to bug 444664 it happens
+ ; so rarely it isn't worth working around it by reading the registry values.
+ ${WinVerGetMajor} $0
+ ${WinVerGetMinor} $1
+ ${WinVerGetBuild} $2
+ ${WinVerGetServicePackLevel} $3
+ StrCpy $R1 "${URLUninstallSurvey}$0.$1.$2.$3"
+
+ ; We can't just open the URL normally because we are most likely running
+ ; elevated without an unelevated process to redirect through, and we're
+ ; not going to go around starting elevated web browsers. But to start an
+ ; unelevated process directly from here we need a pretty nasty hack; see
+ ; the ExecInExplorer plugin code itself for the details.
+ ; If we were the default browser and we've now been uninstalled, we need
+ ; to take steps to make sure the user doesn't see an "open with" dialog;
+ ; they're helping us out by answering this survey, they don't need more
+ ; friction. Sometimes Windows 7 and 8 automatically switch the default to
+ ; IE, but it isn't reliable, so we'll manually invoke IE in that case.
+ ; Windows 10 always seems to just clear the default browser, so for it
+ ; we'll manually invoke Edge using Edge's custom URI scheme.
+ ${If} ${AtLeastWin10}
+ ExecInExplorer::Exec "microsoft-edge:$R1"
+ ${Else}
+ ExecInExplorer::Exec "iexplore.exe" /cmdargs "$R1"
+ ${EndIf}
+ ${EndIf}
+
+ ; Finally send the ping, there's no GUI to freeze in case it is slow.
+ ${If} $ShouldSendPing == "1"
+ Call un.SendUninstallPing
+ ${EndIf}
+FunctionEnd
diff --git a/browser/installer/windows/nsis/updater_append.ini b/browser/installer/windows/nsis/updater_append.ini
new file mode 100644
index 0000000000..af7742c12c
--- /dev/null
+++ b/browser/installer/windows/nsis/updater_append.ini
@@ -0,0 +1,12 @@
+
+; IMPORTANT: This file should always start with a newline in case a locale
+; provided updater.ini does not end with a newline.
+; Application to launch after an update has been successfully applied. This
+; must be in the same directory or a sub-directory of the directory of the
+; application executable that initiated the software update.
+[PostUpdateWin]
+; ExeRelPath is the path to the PostUpdateWin executable relative to the
+; application executable.
+ExeRelPath=uninstall\helper.exe
+; ExeArg is the argument to pass to the PostUpdateWin exe
+ExeArg=/PostUpdate