Bug 1324617 - Allow any of multiple installations to be set as the Windows default browser; r=jimm,rstrong
☠☠ backed out by 12c8e115fb05 ☠ ☠
authorMatt Howell <mhowell@mozilla.com>
Mon, 09 Jan 2017 08:14:00 -0800
changeset 360761 5b0aa267bc532a1c41ec7fa8af2eb5ef665db0c6
parent 360760 da9c1e0ddf0fe3997cdd30c648b4d67b954eab0e
child 360762 cee7ea05a8518cbd4e0f3ee1ac8928763804bd82
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, rstrong
bugs1324617
milestone54.0a1
Bug 1324617 - Allow any of multiple installations to be set as the Windows default browser; r=jimm,rstrong Previously each new installation of any Firefox channel in any location would just overwrite the Windows registry keys which register us as a candidate for the default browser setting and for all of our potential file and protocol associations. This meant that only the most recent installation (across all channels) was ever selectable in those settings. It also meant that creating a new installation when one was already present tripped Windows 10's shenanigans alarm, because it saw the registration for an existing application getting clobbered by a new one and couldn't tell that they were really the same application. The response to that alarm going off is to reset the default browser to Edge, and maybe or maybe not generate a system notification about that. This is the cause of bug 1324617. Obviously we would like to prevent that outcome. So with this commit we generate new registration entries for each installation, by adding a hash of the install path to the relevant identifiers. MozReview-Commit-ID: Fz1xDtittMi
browser/components/shell/moz.build
browser/components/shell/nsWindowsShellService.cpp
browser/installer/windows/nsis/installer.nsi
browser/installer/windows/nsis/shared.nsh
browser/installer/windows/nsis/stub.nsi
browser/installer/windows/nsis/uninstaller.nsi
other-licenses/nsis/Contrib/CityHash/cityhash/city.h
--- a/browser/components/shell/moz.build
+++ b/browser/components/shell/moz.build
@@ -25,18 +25,22 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT
     XPIDL_SOURCES += [
         'nsIGNOMEShellService.idl',
     ]
 
 XPIDL_MODULE = 'shellservice'
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
+        '../../../other-licenses/nsis/Contrib/CityHash/cityhash/city.cpp',
         'nsWindowsShellService.cpp',
     ]
+    LOCAL_INCLUDES += [
+        '../../../other-licenses/nsis/Contrib/CityHash/cityhash',
+    ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     SOURCES += [
         'nsMacShellService.cpp',
     ]
 elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     SOURCES += [
         'nsGNOMEShellService.cpp',
     ]
--- a/browser/components/shell/nsWindowsShellService.cpp
+++ b/browser/components/shell/nsWindowsShellService.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "nsWindowsShellService.h"
 
+#include "city.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIOutputStream.h"
@@ -91,34 +92,39 @@ OpenKeyForReading(HKEY aKeyRoot, const n
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Default Browser Registry Settings
 //
 // The setting of these values are made by an external binary since writing
 // these values may require elevation.
 //
+// To allow multiple installations to coexist, identifiers written to the
+// registry include a hash of the installation path. This is referred to as
+// <PathHash> in the tables below.
+//
 // - File Extension Mappings
 //   -----------------------
 //   The following file extensions:
-//    .htm .html .shtml .xht .xhtml 
+//    .htm .html .shtml .xht .xhtml
 //   are mapped like so:
 //
-//   HKCU\SOFTWARE\Classes\.<ext>\      (default)         REG_SZ     FirefoxHTML
+//   HKCU\SOFTWARE\Classes\.<ext>\      (default)         REG_SZ     FirefoxHTML-<PathHash>
 //
 //   as aliases to the class:
 //
-//   HKCU\SOFTWARE\Classes\FirefoxHTML\
+//   HKCU\SOFTWARE\Classes\FirefoxHTML-<PathHash>\
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
 //     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
 //     shell\open\ddeexec               (default)         REG_SZ     <empty string>
 //
 // - Windows Vista and above Protocol Handler
 //
-//   HKCU\SOFTWARE\Classes\FirefoxURL\  (default)         REG_SZ     <appname> URL
+//   HKCU\SOFTWARE\Classes\FirefoxURL-<PathHash>\
+//                                      (default)         REG_SZ     <appname> URL
 //                                      EditFlags         REG_DWORD  2
 //                                      FriendlyTypeName  REG_SZ     <appname> URL
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
 //     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
 //     shell\open\ddeexec               (default)         REG_SZ     <empty string>
 //
 // - Protocol Mappings
 //   -----------------
@@ -130,39 +136,59 @@ OpenKeyForReading(HKEY aKeyRoot, const n
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
 //     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
 //     shell\open\ddeexec               (default)         REG_SZ     <empty string>
 //
 // - Windows Start Menu (XP SP1 and newer)
 //   -------------------------------------------------
 //   The following keys are set to make Firefox appear in the Start Menu as the
 //   browser:
-//   
-//   HKCU\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\
+//
+//   HKCU\SOFTWARE\Clients\StartMenuInternet\<appname>-<PathHash>\
 //                                      (default)         REG_SZ     <appname>
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,0
 //     InstallInfo                      HideIconsCommand  REG_SZ     <uninstpath> /HideShortcuts
 //     InstallInfo                      IconsVisible      REG_DWORD  1
 //     InstallInfo                      ReinstallCommand  REG_SZ     <uninstpath> /SetAsDefaultAppGlobal
 //     InstallInfo                      ShowIconsCommand  REG_SZ     <uninstpath> /ShowShortcuts
 //     shell\open\command               (default)         REG_SZ     <apppath>
 //     shell\properties                 (default)         REG_SZ     <appname> &Options
 //     shell\properties\command         (default)         REG_SZ     <apppath> -preferences
 //     shell\safemode                   (default)         REG_SZ     <appname> &Safe Mode
 //     shell\safemode\command           (default)         REG_SZ     <apppath> -safe-mode
 //
+// - RegisteredApplications
+//   -------------------------------------------------
+//   This entry creates the listing in Default Apps for Windows 8 and up and in
+//   Set Program Access and Defaults (SPAD) on older versions.
+//
+//   HKCU\Software\RegisteredApplications\
+//     Firefox-<PathHash>  REG_SZ "Software\Clients\StartMenuInternet\<appname>-<PathHash>\Capabilities"
+//   HKCU\Software\Clients\StartMenuInternet\<appname>-<PathHash>\Capabilities\
+//                                      ApplicationDescription  REG_SZ  <branding description>
+//                                      ApplicationIcon         REG_SZ  <apppath>,0
+//                                      ApplicationName         REG_SZ  <appname>
+//     FileAssociations                 .htm                    REG_SZ  FirefoxHTML-<PathHash>
+//     FileAssociations                 .html                   REG_SZ  FirefoxHTML-<PathHash>
+//     FileAssociations                 .shtml                  REG_SZ  FirefoxHTML-<PathHash>
+//     FileAssociations                 .xht                    REG_SZ  FirefoxHTML-<PathHash>
+//     FileAssociations                 .xhtml                  REG_SZ  FirefoxHTML-<PathHash>
+//     StartMenu                        StartMenuInternet       REG_SZ  <appname>-<PathHash>
+//     URLAssociations                  ftp                     REG_SZ  FirefoxURL-<PathHash>
+//     URLAssociations                  http                    REG_SZ  FirefoxURL-<PathHash>
+//     URLAssociations                  https                   REG_SZ  FirefoxURL-<PathHash>
 
 // The values checked are all default values so the value name is not needed.
 typedef struct {
   const char* keyName;
   const char* valueData;
   const char* oldValueData;
 } SETTING;
 
-#define APP_REG_NAME L"Firefox"
+#define APP_REG_NAME_BASE L"Firefox-"
 #define VAL_FILE_ICON "%APPPATH%,1"
 #define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
 #define OLD_VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
 #define DI "\\DefaultIcon"
 #define SOC "\\shell\\open\\command"
 #define SOD "\\shell\\open\\ddeexec"
 // Used for updating the FTP protocol handler's shell open command under HKCU.
 #define FTP_SOC L"Software\\Classes\\ftp\\shell\\open\\command"
@@ -210,17 +236,17 @@ static SETTING gDDESettings[] = {
   { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
 };
 
 nsresult
 GetHelperPath(nsAutoString& aPath)
 {
   nsresult rv;
-  nsCOMPtr<nsIProperties> directoryService = 
+  nsCOMPtr<nsIProperties> directoryService =
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFile> appHelper;
   rv = directoryService->Get(XRE_EXECUTABLE_FILE,
                              NS_GET_IID(nsIFile),
                              getter_AddRefs(appHelper));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -336,17 +362,17 @@ IsAARDefault(const RefPtr<IApplicationAs
   ASSOCIATIONTYPE queryType = isProtocol ? AT_URLPROTOCOL : AT_FILEEXTENSION;
   HRESULT hr = pAAR->QueryCurrentDefault(aClassName, queryType, AL_EFFECTIVE,
                                          &registeredApp);
   if (FAILED(hr)) {
     return false;
   }
 
   LPCWSTR progID = isProtocol ? L"FirefoxURL" : L"FirefoxHTML";
-  bool isDefault = !wcsicmp(registeredApp, progID);
+  bool isDefault = !wcsnicmp(registeredApp, progID, wcslen(progID));
   CoTaskMemFree(registeredApp);
 
   return isDefault;
 }
 
 static void
 IsDefaultBrowserWin8(bool aCheckAllTypes, bool* aIsDefaultBrowser)
 {
@@ -365,16 +391,48 @@ IsDefaultBrowserWin8(bool aCheckAllTypes
     *aIsDefaultBrowser = res;
   }
   res = IsAARDefault(pAAR, L".html");
   if (*aIsDefaultBrowser && aCheckAllTypes) {
     *aIsDefaultBrowser = res;
   }
 }
 
+static nsresult
+GetAppRegName(nsAutoString &aAppRegName)
+{
+  nsresult rv;
+  nsCOMPtr<nsIProperties> dirSvc =
+    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFile> exeFile;
+  rv = dirSvc->Get(XRE_EXECUTABLE_FILE,
+                   NS_GET_IID(nsIFile),
+                   getter_AddRefs(exeFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFile> appDir;
+  rv = exeFile->GetParent(getter_AddRefs(appDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString path;
+  rv = appDir->GetPath(path);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint64_t hash = CityHash64(static_cast<const char *>(path.get()),
+                             path.Length() * sizeof(nsAutoString::char_type));
+
+  aAppRegName = APP_REG_NAME_BASE;
+  aAppRegName.AppendInt((int)hash, 16);
+  aAppRegName.AppendInt((int)(hash >> 32), 16);
+
+  return rv;
+}
+
 /*
  * Query's the AAR for the default status.
  * This only checks for FirefoxURL and if aCheckAllTypes is set, then
  * it also checks for FirefoxHTML.  Note that those ProgIDs are shared
  * by all Firefox browsers.
 */
 bool
 nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
@@ -387,18 +445,20 @@ nsWindowsShellService::IsDefaultBrowserV
                                 IID_IApplicationAssociationRegistration,
                                 getter_AddRefs(pAAR));
   if (FAILED(hr)) {
     return false;
   }
 
   if (aCheckAllTypes) {
     BOOL res;
+    nsAutoString appRegName;
+    GetAppRegName(appRegName);
     hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
-                                    APP_REG_NAME,
+                                    appRegName.get(),
                                     &res);
     *aIsDefaultBrowser = res;
   } else if (!IsWin8OrLater()) {
     *aIsDefaultBrowser = IsAARDefault(pAAR, L"http");
   }
 
   return true;
 }
@@ -632,17 +692,19 @@ nsWindowsShellService::LaunchControlPane
 {
   IApplicationAssociationRegistrationUI* pAARUI;
   HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI,
                                 NULL,
                                 CLSCTX_INPROC,
                                 IID_IApplicationAssociationRegistrationUI,
                                 (void**)&pAARUI);
   if (SUCCEEDED(hr)) {
-    hr = pAARUI->LaunchAdvancedAssociationUI(APP_REG_NAME);
+    nsAutoString appRegName;
+    GetAppRegName(appRegName);
+    hr = pAARUI->LaunchAdvancedAssociationUI(appRegName.get());
     pAARUI->Release();
   }
   return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsWindowsShellService::LaunchControlPanelDefaultPrograms()
 {
@@ -654,24 +716,27 @@ nsWindowsShellService::LaunchControlPane
   LPCWSTR controlEXE = L"control.exe";
   if (wcslen(controlEXEPath) + wcslen(controlEXE) >= MAX_PATH) {
     return NS_ERROR_FAILURE;
   }
   if (!PathAppendW(controlEXEPath, controlEXE)) {
     return NS_ERROR_FAILURE;
   }
 
-  WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page "
-    "pageDefaultProgram\\pageAdvancedSettings?pszAppName=" APP_REG_NAME;
+  nsAutoString params(NS_LITERAL_STRING("control.exe /name Microsoft.DefaultPrograms "
+    "/page pageDefaultProgram\\pageAdvancedSettings?pszAppName="));
+  nsAutoString appRegName;
+  GetAppRegName(appRegName);
+  params.Append(appRegName);
   STARTUPINFOW si = {sizeof(si), 0};
   si.dwFlags = STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_SHOWDEFAULT;
   PROCESS_INFORMATION pi = {0};
-  if (!CreateProcessW(controlEXEPath, params, nullptr, nullptr, FALSE,
-                      0, nullptr, nullptr, &si, &pi)) {
+  if (!CreateProcessW(controlEXEPath, static_cast<LPWSTR>(params.get()), nullptr,
+                      nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
     return NS_ERROR_FAILURE;
   }
   CloseHandle(pi.hProcess);
   CloseHandle(pi.hThread);
 
   return NS_OK;
 }
 
@@ -790,17 +855,17 @@ nsWindowsShellService::InvokeHTTPOpenAsV
 }
 
 nsresult
 nsWindowsShellService::LaunchHTTPHandlerPane()
 {
   OPENASINFO info;
   info.pcszFile = L"http";
   info.pcszClass = nullptr;
-  info.oaifInFlags = OAIF_FORCE_REGISTRATION | 
+  info.oaifInFlags = OAIF_FORCE_REGISTRATION |
                      OAIF_URL_PROTOCOL |
                      OAIF_REGISTER_EXT;
   return DynSHOpenWithDialog(nullptr, &info);
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
 {
@@ -944,27 +1009,27 @@ WriteBitmap(nsIFile* aFile, imgIContaine
   }
 
   dataSurface->Unmap();
 
   return rv;
 }
 
 NS_IMETHODIMP
-nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement, 
+nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement,
                                             int32_t aPosition)
 {
   nsresult rv;
 
   nsCOMPtr<imgIContainer> container;
   nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(aElement));
   if (!imgElement) {
     // XXX write background loading stuff!
     return NS_ERROR_NOT_AVAILABLE;
-  } 
+  }
   else {
     nsCOMPtr<nsIImageLoadingContent> imageContent =
       do_QueryInterface(aElement, &rv);
     if (!imageContent)
       return rv;
 
     // get the image container
     nsCOMPtr<imgIRequest> request;
@@ -981,17 +1046,17 @@ nsWindowsShellService::SetDesktopBackgro
   nsCOMPtr<nsIStringBundleService>
     bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStringBundle> shellBundle;
   rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
                                    getter_AddRefs(shellBundle));
   NS_ENSURE_SUCCESS(rv, rv);
- 
+
   // e.g. "Desktop Background.bmp"
   nsString fileLeafName;
   rv = shellBundle->GetStringFromName
                       (u"desktopBackgroundLeafNameWin",
                        getter_Copies(fileLeafName));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // get the profile root directory
@@ -1069,22 +1134,22 @@ nsWindowsShellService::OpenApplication(i
     application.AssignLiteral("Mail");
     break;
   case nsIShellService::APPLICATION_NEWS:
     application.AssignLiteral("News");
     break;
   }
 
   // The Default Client section of the Windows Registry looks like this:
-  // 
+  //
   // Clients\aClient\
   //  e.g. aClient = "Mail"...
   //        \Mail\(default) = Client Subkey Name
   //             \Client Subkey Name
-  //             \Client Subkey Name\shell\open\command\ 
+  //             \Client Subkey Name\shell\open\command\
   //             \Client Subkey Name\shell\open\command\(default) = path to exe
   //
 
   // Find the default application for this class.
   HKEY theKey;
   nsresult rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
   if (NS_FAILED(rv))
     return rv;
@@ -1114,35 +1179,35 @@ nsWindowsShellService::OpenApplication(i
   res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
                            &type, (LPBYTE)&buf, &len);
   if (REG_FAILED(res) || !*buf)
     return NS_ERROR_FAILURE;
 
   // Close the key we opened.
   ::RegCloseKey(theKey);
 
-  // Look for any embedded environment variables and substitute their 
+  // Look for any embedded environment variables and substitute their
   // values, as |::CreateProcessW| is unable to do this.
   nsAutoString path(buf);
   int32_t end = path.Length();
   int32_t cursor = 0, temp = 0;
   ::ZeroMemory(buf, sizeof(buf));
   do {
     cursor = path.FindChar('%', cursor);
-    if (cursor < 0) 
+    if (cursor < 0)
       break;
 
     temp = path.FindChar('%', cursor + 1);
     ++cursor;
 
     ::ZeroMemory(&buf, sizeof(buf));
 
     ::GetEnvironmentVariableW(nsAutoString(Substring(path, cursor, temp - cursor)).get(),
                               buf, sizeof(buf));
-    
+
     // "+ 2" is to subtract the extra characters used to delimit the environment
     // variable ('%').
     path.Replace((cursor - 1), temp - cursor + 2, nsDependentString(buf));
 
     ++cursor;
   }
   while (cursor < end);
 
@@ -1208,25 +1273,25 @@ nsWindowsShellService::~nsWindowsShellSe
 {
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
                                               const nsACString& aURI)
 {
   nsresult rv;
-  nsCOMPtr<nsIProcess> process = 
+  nsCOMPtr<nsIProcess> process =
     do_CreateInstance("@mozilla.org/process/util;1", &rv);
   if (NS_FAILED(rv))
     return rv;
-  
+
   rv = process->Init(aApplication);
   if (NS_FAILED(rv))
     return rv;
-  
+
   const nsCString spec(aURI);
   const char* specStr = spec.get();
   return process->Run(false, &specStr, 1);
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::GetDefaultFeedReader(nsIFile** _retval)
 {
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -377,66 +377,74 @@ Section "-Application" APP_IDX
   ; On install always add the FirefoxHTML 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" "$2" "$8,1" \
+  ${AddDisabledDDEHandlerValues} "FirefoxHTML-$AppUserModelID" "$2" "$8,1" \
                                  "${AppRegName} Document" ""
-  ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
-                                 "true"
+  ${AddDisabledDDEHandlerValues} "FirefoxURL-$AppUserModelID" "$2" "$8,1" \
+                                 "${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 get set in both HKLM and HKCU.
+  ; For post win8, the keys below can be set in HKCU if needed.
   ${If} $TmpVal == "HKLM"
     ; Set the Start Menu Internet and Vista Registered App HKLM registry keys.
-    ${SetStartMenuInternet} "HKLM"
-    ${FixShellIconHandler} "HKLM"
+    ; If we're upgrading an existing install, replacing the old registry entries
+    ; (without a path hash) would cause the default browser to be reset.
+    ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\FIREFOX.EXE\DefaultIcon" ""
+    StrCpy $0 $0 -2
+    ${If} $0 != "$INSTDIR\${FileMainEXE}"
+      ${SetStartMenuInternet} "HKLM"
+      ${FixShellIconHandler} "HKLM"
+    ${EndIf}
 
     ; If we are writing to HKLM and create either the desktop or start menu
     ; shortcuts set IconsVisible to 1 otherwise to 0.
     ; Taskbar shortcuts imply having a start menu shortcut.
-    ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
-    StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
+    StrCpy $0 "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\InstallInfo"
     ${If} $AddDesktopSC == 1
     ${OrIf} $AddStartMenuSC == 1
     ${OrIf} $AddTaskbarSC == 1
       WriteRegDWORD HKLM "$0" "IconsVisible" 1
     ${Else}
       WriteRegDWORD HKLM "$0" "IconsVisible" 0
     ${EndIf}
-  ${EndIf}
-
-  ${If} ${AtLeastWin8}
+  ${ElseIf} ${AtLeastWin8}
     ; Set the Start Menu Internet and Vista Registered App HKCU registry keys.
-    ${SetStartMenuInternet} "HKCU"
-    ${FixShellIconHandler} "HKCU"
+    ; If we're upgrading an existing install, replacing the old registry entries
+    ; (without a path hash) would cause the default browser to be reset.
+    ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\FIREFOX.EXE\DefaultIcon" ""
+    StrCpy $0 $0 -2
+    ${If} $0 != "$INSTDIR\${FileMainEXE}"
+      ${SetStartMenuInternet} "HKCU"
+      ${FixShellIconHandler} "HKCU"
+    ${EndIf}
 
     ; If we create either the desktop or start menu shortcuts, then
     ; set IconsVisible to 1 otherwise to 0.
     ; Taskbar shortcuts imply having a start menu shortcut.
-    ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
-    StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
+    StrCpy $0 "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\InstallInfo"
     ${If} $AddDesktopSC == 1
     ${OrIf} $AddStartMenuSC == 1
     ${OrIf} $AddTaskbarSC == 1
       WriteRegDWORD HKCU "$0" "IconsVisible" 1
     ${Else}
       WriteRegDWORD HKCU "$0" "IconsVisible" 0
     ${EndIf}
   ${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 
+  ; 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 
+  ; 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"
       ; On Windows < XP SP3 we do not install the maintenance service.
@@ -450,17 +458,17 @@ Section "-Application" APP_IDX
     ${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. 
+    ; 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.
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -8,16 +8,17 @@
   ; Otherwise ApplicationID::Set can fail intermittently with a file in use error.
   System::Call "kernel32::GetCurrentProcessId() i.r0"
   System::Call "kernel32::ProcessIdToSessionId(i $0, *i ${NSIS_MAX_STRLEN} r9)"
 
   ; Determine if we're the protected UserChoice default or not. If so fix the
   ; start menu tile.  In case there are 2 Firefox installations, we only do
   ; this if the application being updated is the default.
   ReadRegStr $0 HKCU "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" "ProgId"
+  ${WordFind} "$0" "-" "+1{" $0
   ${If} $0 == "FirefoxURL"
   ${AndIf} $9 != 0 ; We're not running in session 0
     ReadRegStr $0 HKCU "Software\Classes\FirefoxURL\shell\open\command" ""
     ${GetPathFromString} "$0" $0
     ${GetParent} "$0" $0
     ${If} ${FileExists} "$0"
       ${GetLongPath} "$0" $0
     ${EndIf}
@@ -54,45 +55,16 @@
     ${SetAppLSPCategories} ${LSP_CATEGORIES}
 
     ; Win7 taskbar and start menu link maintenance
     Call FixShortcutAppModelIDs
 
     ; Add the Firewall entries after an update
     Call AddFirewallEntries
 
-    ; Only update the Clients\StartMenuInternet registry key values in HKLM if
-    ; they don't exist or this installation is the same as the one set in those
-    ; keys.
-    ${StrFilter} "${FileMainEXE}" "+" "" "" $1
-    ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$1\DefaultIcon" ""
-    ${GetPathFromString} "$0" $0
-    ${GetParent} "$0" $0
-    ${If} ${FileExists} "$0"
-      ${GetLongPath} "$0" $0
-    ${EndIf}
-    ${If} "$0" == "$INSTDIR"
-      ${SetStartMenuInternet} "HKLM"
-    ${EndIf}
-
-    ; Only update the Clients\StartMenuInternet registry key values in HKCU if
-    ; they don't exist or this installation is the same as the one set in those
-    ; keys.  This is only done in Windows 8 to avoid a UAC prompt.
-    ${If} ${AtLeastWin8}
-      ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$1\DefaultIcon" ""
-      ${GetPathFromString} "$0" $0
-      ${GetParent} "$0" $0
-      ${If} ${FileExists} "$0"
-        ${GetLongPath} "$0" $0
-      ${EndIf}
-      ${If} "$0" == "$INSTDIR"
-        ${SetStartMenuInternet} "HKCU"
-      ${EndIf}
-    ${EndIf}
-
     ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
     ${If} "$0" != "${GREVersion}"
       WriteRegStr HKLM "Software\mozilla.org\Mozilla" "CurrentVersion" "${GREVersion}"
     ${EndIf}
   ${EndIf}
 
   ; Migrate the application's Start Menu directory to a single shortcut in the
   ; root of the Start Menu Programs directory.
@@ -176,17 +148,17 @@
   ${RemoveDeprecatedKeys} ; Does not use SHCTX
 
   SetShellVarContext all      ; Set SHCTX to all users (e.g. HKLM)
   ${SetHandlers} ; Uses SHCTX
   ${SetStartMenuInternet} "HKLM"
   ${FixShellIconHandler} "HKLM"
   ${ShowShortcuts}
   ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
-  WriteRegStr HKLM "Software\Clients\StartMenuInternet" "" "$R9"
+  WriteRegStr HKLM "Software\Clients\StartMenuInternet" "" "$R9-$AppUserModelID"
 !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
   ${StrFilter} "${FileMainEXE}" "+" "" "" $0
@@ -246,18 +218,17 @@
     ${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
-  ${StrFilter} "${FileMainEXE}" "+" "" "" $0
-  StrCpy $R1 "Software\Clients\StartMenuInternet\$0\InstallInfo"
+  StrCpy $R1 "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\InstallInfo"
   WriteRegDWORD HKLM "$R1" "IconsVisible" 1
   ${If} ${AtLeastWin8}
     WriteRegDWORD HKCU "$R1" "IconsVisible" 1
   ${EndIf}
 
   SetShellVarContext all  ; Set $DESKTOP to All Users
   ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk"
     CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}"
@@ -322,102 +293,107 @@
   ${EndUnless}
 !macroend
 !define ShowShortcuts "!insertmacro ShowShortcuts"
 
 !macro AddAssociationIfNoneExist FILE_TYPE
   ClearErrors
   EnumRegKey $7 HKCR "${FILE_TYPE}" 0
   ${If} ${Errors}
-    WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}"  "" "FirefoxHTML"
+    WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}"  "" "FirefoxHTML-$AppUserModelID"
   ${EndIf}
-  WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}\OpenWithProgids" "FirefoxHTML" ""
+  WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}\OpenWithProgids" "FirefoxHTML-$AppUserModelID" ""
 !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
 
   StrCpy $0 "SOFTWARE\Classes"
   StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
 
-  ; Associate the file handlers with FirefoxHTML
+  ; 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"
+    WriteRegStr SHCTX "$0\.htm"   "" "FirefoxHTML-$AppUserModelID"
   ${EndIf}
 
   ReadRegStr $6 SHCTX "$0\.html" ""
+  ${WordFind} "$6" "-" "+1{" $6
   ${If} "$6" != "FirefoxHTML"
-    WriteRegStr SHCTX "$0\.html"  "" "FirefoxHTML"
+    WriteRegStr SHCTX "$0\.html"  "" "FirefoxHTML-$AppUserModelID"
   ${EndIf}
 
   ReadRegStr $6 SHCTX "$0\.shtml" ""
+  ${WordFind} "$6" "-" "+1{" $6
   ${If} "$6" != "FirefoxHTML"
-    WriteRegStr SHCTX "$0\.shtml" "" "FirefoxHTML"
+    WriteRegStr SHCTX "$0\.shtml" "" "FirefoxHTML-$AppUserModelID"
   ${EndIf}
 
   ReadRegStr $6 SHCTX "$0\.xht" ""
+  ${WordFind} "$6" "-" "+1{" $6
   ${If} "$6" != "FirefoxHTML"
-    WriteRegStr SHCTX "$0\.xht"   "" "FirefoxHTML"
+    WriteRegStr SHCTX "$0\.xht"   "" "FirefoxHTML-$AppUserModelID"
   ${EndIf}
 
   ReadRegStr $6 SHCTX "$0\.xhtml" ""
+  ${WordFind} "$6" "-" "+1{" $6
   ${If} "$6" != "FirefoxHTML"
-    WriteRegStr SHCTX "$0\.xhtml" "" "FirefoxHTML"
+    WriteRegStr SHCTX "$0\.xhtml" "" "FirefoxHTML-$AppUserModelID"
   ${EndIf}
 
   ${AddAssociationIfNoneExist} ".pdf"
   ${AddAssociationIfNoneExist} ".oga"
   ${AddAssociationIfNoneExist} ".ogg"
   ${AddAssociationIfNoneExist} ".ogv"
   ${AddAssociationIfNoneExist} ".pdf"
   ${AddAssociationIfNoneExist} ".webm"
 
   ; An empty string is used for the 5th param because FirefoxHTML is not a
   ; protocol handler
-  ${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
+  ${AddDisabledDDEHandlerValues} "FirefoxHTML-$AppUserModelID" "$2" "$8,1" \
                                  "${AppRegName} HTML Document" ""
 
-  ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
+  ${AddDisabledDDEHandlerValues} "FirefoxURL-$AppUserModelID" "$2" "$8,1" "${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} "ftp" "$2" "$8,1" "" ""
   ${AddDisabledDDEHandlerValues} "http" "$2" "$8,1" "" ""
   ${AddDisabledDDEHandlerValues} "https" "$2" "$8,1" "" ""
 !macroend
 !define SetHandlers "!insertmacro SetHandlers"
 
-; Adds the HKLM\Software\Clients\StartMenuInternet\FIREFOX.EXE registry
+; 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.
-; http://support.microsoft.com/kb/297878
 ;
 ; 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.
 ;
-; Note: we might be able to get away with using the full path to the
-; application executable for the key name in order to support multiple
-; installations.
+; 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
 
-  ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
-
-  StrCpy $0 "Software\Clients\StartMenuInternet\$R9"
+  StrCpy $0 "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID"
 
   WriteRegStr ${RegKey} "$0" "" "${BrandFullName}"
 
   WriteRegStr ${RegKey} "$0\DefaultIcon" "" "$8,0"
 
   ; 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"
@@ -444,45 +420,45 @@
   WriteRegStr ${RegKey} "$0\shell\safemode" "" "$(CONTEXT_SAFE_MODE)"
   WriteRegStr ${RegKey} "$0\shell\safemode\command" "" "$\"$8$\" -safe-mode"
 
   ; Vista Capabilities registry keys
   WriteRegStr ${RegKey} "$0\Capabilities" "ApplicationDescription" "$(REG_APP_DESC)"
   WriteRegStr ${RegKey} "$0\Capabilities" "ApplicationIcon" "$8,0"
   WriteRegStr ${RegKey} "$0\Capabilities" "ApplicationName" "${BrandShortName}"
 
-  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".htm"   "FirefoxHTML"
-  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".html"  "FirefoxHTML"
-  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".shtml" "FirefoxHTML"
-  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".xht"   "FirefoxHTML"
-  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".xhtml" "FirefoxHTML"
+  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".htm"   "FirefoxHTML-$AppUserModelID"
+  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".html"  "FirefoxHTML-$AppUserModelID"
+  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".shtml" "FirefoxHTML-$AppUserModelID"
+  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".xht"   "FirefoxHTML-$AppUserModelID"
+  WriteRegStr ${RegKey} "$0\Capabilities\FileAssociations" ".xhtml" "FirefoxHTML-$AppUserModelID"
 
-  WriteRegStr ${RegKey} "$0\Capabilities\StartMenu" "StartMenuInternet" "$R9"
+  WriteRegStr ${RegKey} "$0\Capabilities\StartMenu" "StartMenuInternet" "${AppRegName}-$AppUserModelID"
 
-  WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "ftp"    "FirefoxURL"
-  WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "http"   "FirefoxURL"
-  WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "https"  "FirefoxURL"
+  WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "ftp"    "FirefoxURL-$AppUserModelID"
+  WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "http"   "FirefoxURL-$AppUserModelID"
+  WriteRegStr ${RegKey} "$0\Capabilities\URLAssociations" "https"  "FirefoxURL-$AppUserModelID"
 
   ; Vista Registered Application
-  WriteRegStr ${RegKey} "Software\RegisteredApplications" "${AppRegName}" "$0\Capabilities"
+  WriteRegStr ${RegKey} "Software\RegisteredApplications" "${AppRegName}-$AppUserModelID" "$0\Capabilities"
 !macroend
 !define SetStartMenuInternet "!insertmacro SetStartMenuInternet"
 
 ; 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
   ClearErrors
-  ReadRegStr $1 ${RegKey} "Software\Classes\FirefoxHTML\ShellEx\IconHandler" ""
+  ReadRegStr $1 ${RegKey} "Software\Classes\FirefoxHTML-$AppUserModelID\ShellEx\IconHandler" ""
   ${Unless} ${Errors}
-    ReadRegStr $1 ${RegKey} "Software\Classes\FirefoxHTML\DefaultIcon" ""
+    ReadRegStr $1 ${RegKey} "Software\Classes\FirefoxHTML-$AppUserModelID\DefaultIcon" ""
     ${GetLongPath} "$INSTDIR\${FileMainEXE}" $2
     ${If} "$1" != "$2,1"
-      WriteRegStr ${RegKey} "Software\Classes\FirefoxHTML\DefaultIcon" "" "$2,1"
+      WriteRegStr ${RegKey} "Software\Classes\FirefoxHTML-$AppUserModelID\DefaultIcon" "" "$2,1"
     ${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
@@ -613,17 +589,19 @@
 ; 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"
@@ -681,27 +659,27 @@
 !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" $R9
+  ${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" "$2" "$8,1" \
+    ${AddDisabledDDEHandlerValues} "FirefoxHTML-$AppUserModelID" "$2" "$8,1" \
                                    "${AppRegName} HTML Document" ""
   ${EndIf}
 
-  ${IsHandlerForInstallDir} "FirefoxURL" $R9
+  ${IsHandlerForInstallDir} "FirefoxURL-$AppUserModelID" $R9
   ${If} "$R9" == "true"
-    ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" \
+    ${AddDisabledDDEHandlerValues} "FirefoxURL-$AppUserModelID" "$2" "$8,1" \
                                    "${AppRegName} URL" "true"
   ${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"
@@ -766,43 +744,23 @@
   Pop $R0
 !macroend
 !define AddMaintCertKeys "!insertmacro AddMaintCertKeys"
 !endif
 
 ; Removes various registry entries for reasons noted below (does not use SHCTX).
 !macro RemoveDeprecatedKeys
   StrCpy $0 "SOFTWARE\Classes"
-  ; Remove support for launching gopher urls from the shell during install or
-  ; update if the DefaultIcon is from firefox.exe.
-  ${RegCleanAppHandler} "gopher"
-
   ; 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"
-
-  ; Delete gopher from Capabilities\URLAssociations if it is present.
-  ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
-  StrCpy $0 "Software\Clients\StartMenuInternet\$R9"
-  ClearErrors
-  ReadRegStr $2 HKLM "$0\Capabilities\URLAssociations" "gopher"
-  ${Unless} ${Errors}
-    DeleteRegValue HKLM "$0\Capabilities\URLAssociations" "gopher"
-  ${EndUnless}
-
-  ; Delete gopher from the user's UrlAssociations if it points to FirefoxURL.
-  StrCpy $0 "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\gopher"
-  ReadRegStr $2 HKCU "$0\UserChoice" "Progid"
-  ${If} "$2" == "FirefoxURL"
-    DeleteRegKey HKCU "$0"
-  ${EndIf}
 !macroend
 !define RemoveDeprecatedKeys "!insertmacro RemoveDeprecatedKeys"
 
 ; Removes various directories and files for reasons noted below.
 !macro RemoveDeprecatedFiles
   ; 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"
@@ -1255,29 +1213,29 @@
 ; plugin for Vista and above. 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
   ; Only set as the user's StartMenuInternet browser if the StartMenuInternet
   ; registry keys are for this install.
   ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
   ClearErrors
-  ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+  ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$R9-$AppUserModelID\DefaultIcon" ""
   ${If} ${Errors}
   ${OrIf} ${AtMostWin2008R2}
     ClearErrors
-    ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+    ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9-$AppUserModelID\DefaultIcon" ""
   ${EndIf}
   ${Unless} ${Errors}
     ${GetPathFromString} "$0" $0
     ${GetParent} "$0" $0
     ${If} ${FileExists} "$0"
       ${GetLongPath} "$0" $0
       ${If} "$0" == "$INSTDIR"
-        WriteRegStr HKCU "Software\Clients\StartMenuInternet" "" "$R9"
+        WriteRegStr HKCU "Software\Clients\StartMenuInternet" "" "$R9-$AppUserModelID"
       ${EndIf}
     ${EndIf}
   ${EndUnless}
 
   SetShellVarContext current  ; Set SHCTX to the current user (e.g. HKCU)
 
   ${If} ${AtLeastWin8}
     ${SetStartMenuInternet} "HKCU"
@@ -1288,21 +1246,21 @@ Function SetAsDefaultAppUserHKCU
   ${SetHandlers}
 
   ${If} ${AtLeastWinVista}
     ; Only register as the handler on Vista and above 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" "${AppRegName}"
+    ReadRegStr $0 HKLM "Software\RegisteredApplications" "${AppRegName}-$AppUserModelID"
     ${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::SetAppAsDefaultAll "${AppRegName}"
+      AppAssocReg::SetAppAsDefaultAll "${AppRegName}-$AppUserModelID"
     ${EndUnless}
   ${EndIf}
   ${RemoveDeprecatedKeys}
   ${MigrateTaskBarShortcut}
 FunctionEnd
 
 ; Helper for updating the shortcut application model IDs.
 Function FixShortcutAppModelIDs
@@ -1346,23 +1304,22 @@ Function SetAsDefaultAppUser
   ${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 the StartMenuInternet client
-  ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
   ClearErrors
-  ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+  ReadRegStr $0 HKCU "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\DefaultIcon" ""
   ${If} ${Errors}
   ${OrIf} ${AtMostWin2008R2}
     ClearErrors
-    ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
+    ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\${AppRegName}-$AppUserModelID\DefaultIcon" ""
   ${EndIf}
 
   ${Unless} ${Errors}
     ${GetPathFromString} "$0" $0
     ${GetParent} "$0" $0
     ${If} ${FileExists} "$0"
       ${GetLongPath} "$0" $0
       ${If} "$0" == "$INSTDIR"
--- a/browser/installer/windows/nsis/stub.nsi
+++ b/browser/installer/windows/nsis/stub.nsi
@@ -680,46 +680,35 @@ Function SendPing
           StrCpy $R2 "0"
         ${EndIf}
       ${EndIf}
     ${Else}
       StrCpy $R2 "0" ; Firefox is not set as default.
     ${EndIf}
 
     ${If} "$R2" == "0"
-    ${AndIf} ${AtLeastWinVista}
-      ; Check to see if this install location is currently set as the default
-      ; browser by Default Programs which is only available on Vista and above.
-      ClearErrors
-      ReadRegStr $R3 HKLM "Software\RegisteredApplications" "${AppRegName}"
-      ${Unless} ${Errors}
-        AppAssocReg::QueryAppIsDefaultAll "${AppRegName}" "effective"
-        Pop $R3
-        ${If} $R3 == "1"
-          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}
+      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" ; Firefox is not set as default.
+            StrCpy $R2 "0"
           ${EndIf}
         ${EndIf}
-      ${EndUnless}
+      ${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}
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -166,17 +166,17 @@ UninstPage custom un.preConfirm
 
 ; Use the default dialog for IDD_VERIFY for a simple Banner
 ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe"
 
 ################################################################################
 # Helper Functions
 
 ; This function is used to uninstall the maintenance service if the
-; application currently being uninstalled is the last application to use 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
 
@@ -194,16 +194,17 @@ Function un.UninstallServiceIfNotUsed
     ${EndIf}
     IntOp $0 $0 + 1
   ${Loop}
 
   ; Restore back the registry view
   ${If} ${RunningX64}
     SetRegView lastUsed
   ${EndIf}
+
   ${If} $0 == 0
     ; Get the path of the maintenance service uninstaller
     ReadRegStr $1 HKLM ${MaintUninstallKey} "UninstallString"
 
     ; If the uninstall string does not exist, skip executing it
     StrCmp $1 "" doneUninstall
 
     ; $1 is already a quoted string pointing to the install path
@@ -273,76 +274,63 @@ Section "Uninstall"
     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} "FirefoxURL"
-  ${un.RegCleanAppHandler} "FirefoxHTML"
+  ${un.RegCleanAppHandler} "FirefoxURL-$AppUserModelID"
+  ${un.RegCleanAppHandler} "FirefoxHTML-$AppUserModelID"
   ${un.RegCleanProtocolHandler} "ftp"
   ${un.RegCleanProtocolHandler} "http"
   ${un.RegCleanProtocolHandler} "https"
-
-  ClearErrors
-  ReadRegStr $R9 HKCR "FirefoxHTML" ""
-  ; Don't clean up the file handlers if the FirefoxHTML key still exists since
-  ; there should be a second installation that may be the default file handler
-  ${If} ${Errors}
-    ${un.RegCleanFileHandler}  ".htm"   "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".html"  "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".shtml" "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".xht"   "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".xhtml" "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".oga"  "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".ogg"  "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".ogv"  "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".pdf"  "FirefoxHTML"
-    ${un.RegCleanFileHandler}  ".webm"  "FirefoxHTML"
-  ${EndIf}
+  ${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}  ".pdf"  "FirefoxHTML-$AppUserModelID"
+  ${un.RegCleanFileHandler}  ".webm"  "FirefoxHTML-$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}
 
-  StrCpy $0 "Software\Clients\StartMenuInternet\${FileMainEXE}\shell\open\command"
-  ReadRegStr $R1 HKLM "$0" ""
-  ${un.RemoveQuotesFromPath} "$R1" $R1
-  ${un.GetParent} "$R1" $R1
+  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"
 
-  ; Only remove the StartMenuInternet key if it refers to this install location.
-  ; The StartMenuInternet registry key is independent of the default browser
-  ; settings. The XPInstall base un-installer always removes this key if it is
-  ; uninstalling the default browser and it will always replace the keys when
-  ; installing even if there is another install of Firefox that is set as the
-  ; default browser. Now the key is always updated on install but it is only
-  ; removed if it refers to this install location.
-  ${If} "$INSTDIR" == "$R1"
-    DeleteRegKey HKLM "Software\Clients\StartMenuInternet\${FileMainEXE}"
+  ; Remove old protocol handler and StartMenuInternet keys without install path
+  ; hashes, but only if they're for this installation.
+  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" "${AppRegName}"
   ${EndIf}
-
-  ReadRegStr $R1 HKCU "$0" ""
-  ${un.RemoveQuotesFromPath} "$R1" $R1
-  ${un.GetParent} "$R1" $R1
-
-  ; Only remove the StartMenuInternet key if it refers to this install location.
-  ; The StartMenuInternet registry key is independent of the default browser
-  ; settings. The XPInstall base un-installer always removes this key if it is
-  ; uninstalling the default browser and it will always replace the keys when
-  ; installing even if there is another install of Firefox that is set as the
-  ; default browser. Now the key is always updated on install but it is only
-  ; removed if it refers to this install location.
-  ${If} "$INSTDIR" == "$R1"
-    DeleteRegKey HKCU "Software\Clients\StartMenuInternet\${FileMainEXE}"
+  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" "${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}"
--- a/other-licenses/nsis/Contrib/CityHash/cityhash/city.h
+++ b/other-licenses/nsis/Contrib/CityHash/cityhash/city.h
@@ -41,25 +41,36 @@
 // doesn't hold for any hash functions in this file.
 
 #ifndef CITY_HASH_H_
 #define CITY_HASH_H_
 
 #include "../CityHash.h" // added by moz, specific to nsis project
 
 #include <stdlib.h>  // for size_t.
-#include <utility>
 
 typedef unsigned __int8 uint8;
 typedef unsigned __int32 uint32;
 typedef unsigned __int64 uint64;
+
+// The standard <utility> header doesn't compile, apparently it conflicts
+// with... some Mozilla something or other. But all that's used from it
+// is std::pair, so we can just replace that with mozilla::Pair.
+#ifndef MOZILLA_CLIENT
+#include <utility>
 typedef std::pair<uint64, uint64> uint128;
-
 inline uint64 Uint128Low64(const uint128& x) { return x.first; }
 inline uint64 Uint128High64(const uint128& x) { return x.second; }
+#else
+#include "mozilla/Pair.h"
+typedef mozilla::Pair<uint64, uint64> uint128;
+inline uint64 Uint128Low64(const uint128& x) { return x.first(); }
+inline uint64 Uint128High64(const uint128& x) { return x.second(); }
+#endif
+
 
 // Hash function for a byte array.
 uint64 CityHash64(const char *buf, size_t len);
 
 // Hash function for a byte array.  For convenience, a 64-bit seed is also
 // hashed into the result.
 uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed);