diff --git a/mozilla/browser/components/nsBrowserContentHandler.js b/mozilla/browser/components/nsBrowserContentHandler.js index ed437412301..1c8737d30c2 100644 --- a/mozilla/browser/components/nsBrowserContentHandler.js +++ b/mozilla/browser/components/nsBrowserContentHandler.js @@ -61,6 +61,8 @@ const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; const nsICategoryManager = Components.interfaces.nsICategoryManager; const nsIWebNavigationInfo = Components.interfaces.nsIWebNavigationInfo; const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService; +const nsITimer = Components.interfaces.nsITimer; +const nsITimerCallback = Components.interfaces.nsITimerCallback; const NS_BINDING_ABORTED = 0x804b0002; const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; @@ -595,16 +597,73 @@ var nsDefaultCommandLineHandler = { QueryInterface : function dch_QI(iid) { if (!iid.equals(nsISupports) && !iid.equals(nsICommandLineHandler) && + !iid.equals(nsITimerCallback) && !iid.equals(nsIFactory)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }, + // True when a DDE request will follow + _requestPending: false, + _URIs: [ ], + _timer: null, + + /* nsITimerCallback - opens urls after the ui is sufficiently initialized */ + notify: function (aTimer) { + try { + var navWin = getMostRecentBrowserWindow(); + var navNav = navWin.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsIWebNavigation); + var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem; + var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsIDOMWindow); + var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow; + if (bwin) { + var browser = navWin.getBrowser(); + var tabPanels = browser.browsers; + var count = this._URIs.length; + for (var i = 0; i < count; ++i) { + var uri = this._URIs[0]; + if (tabPanels.length == 1 && + tabPanels[0].currentURI.spec == "about:blank" && + !tabPanels[0].webProgress.isLoadingDocument) { + if (shouldLoadURI(uri)) + handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_CURRENTWINDOW); + } + else { + handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW); + } + this._URIs.splice(0, 1); + } + this._requestPending = false; + this._timer.cancel(); + this._timer = null; + this._URIs = [ ]; + return; + } + } + catch (e) { + } + }, + /* nsICommandLineHandler */ handle : function dch_handle(cmdLine) { var urilist = []; +#ifdef XP_WIN + if (cmdLine.handleFlag("requestpending", false) && + cmdLine.state == nsICommandLine.STATE_INITIAL_LAUNCH) { + this._requestPending = true; + // When the requestpending flag is present a dde message will follow that + // contains the same url. By handling the url flag here as a noop + // duplicate requests to open the same url are prevented. When the + // application needs to restart during startup the requestpending flag + // is removed and the url flag will be handled normally after the restart. + cmdLine.handleFlagWithParam("url", false); + } +#endif + try { var ar; while ((ar = cmdLine.handleFlagWithParam("url", false))) { @@ -615,6 +674,41 @@ var nsDefaultCommandLineHandler = { Components.utils.reportError(e); } +#ifdef XP_WIN + if (cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT && this._requestPending) { + // Handdle DDE request to open an url by first trying to open it via an + // existing window's openURI. If this fails a timer will be used to allow + // the window to finish opening so the url can be opened correctly and + // respect the OPEN_EXTERNAL pref. + try { + var navWin = getMostRecentBrowserWindow(); + var navNav = navWin.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsIWebNavigation); + var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem; + var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsIDOMWindow); + var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow; + bwin.openURI(urilist[0], null, nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, + nsIBrowserDOMWindow.OPEN_EXTERNAL); + this._requestPending = false; + } + catch (e) { + this._URIs.push(urilist[0]); + // If multiple urls (e.g. local files, etc.) are opened at the same + // time when the app is not running it is possible to have multiple + // requests before there is a window available to handle the request so + // a timer is used to allow the window to finish opening before + // attempting to open the url. + if (!this._timer) { + this._timer = Components.classes["@mozilla.org/timer;1"] + .createInstance(nsITimer); + this._timer.initWithCallback(this, 100, nsITimer.TYPE_REPEATING_SLACK); + } + } + return; + } +#endif + var count = cmdLine.length; for (var i = 0; i < count; ++i) { diff --git a/mozilla/browser/components/shell/src/nsWindowsShellService.cpp b/mozilla/browser/components/shell/src/nsWindowsShellService.cpp index bf61c6b1e73..2a67049f7f8 100644 --- a/mozilla/browser/components/shell/src/nsWindowsShellService.cpp +++ b/mozilla/browser/components/shell/src/nsWindowsShellService.cpp @@ -62,6 +62,9 @@ #include "shlobj.h" #include "nsIWindowsRegKey.h" +#include "windows.h" +#include "shellapi.h" + #include #ifndef MAX_BUF @@ -97,26 +100,40 @@ OpenUserKeyForReading(HKEY aStartKey, const char* aKeyName, HKEY* aKey) return NS_OK; } +// Sets the default browser registry keys for Windows versions prior to Vista. +// Try to open / create the key in HKLM and if that fails try to do the same +// in HKCU. Though this is not strictly the behavior I would expect it is the +// same behavior that IE has when setting the default browser previous to Vista. static nsresult -OpenKeyForWriting(const char* aKeyName, HKEY* aKey, PRBool aForAllUsers, PRBool aCreate) +OpenKeyForWriting(HKEY aStartKey, const char* aKeyName, HKEY* aKey, + PRBool aHKLMOnly) { - nsresult rv = NS_OK; + DWORD dwDisp = 0; + DWORD rv = ::RegCreateKeyEx(aStartKey, aKeyName, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, aKey, &dwDisp); - HKEY rootKey = aForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - DWORD result = ::RegOpenKeyEx(rootKey, aKeyName, 0, KEY_READ | KEY_WRITE, aKey); - - switch (result) { + switch (rv) { case ERROR_SUCCESS: break; case ERROR_ACCESS_DENIED: - return NS_ERROR_FILE_ACCESS_DENIED; + if (aHKLMOnly || aStartKey == HKEY_CURRENT_USER) + return NS_ERROR_FILE_ACCESS_DENIED; + // fallback to HKCU immediately on access denied since we won't be able + // to create the key. + return OpenKeyForWriting(HKEY_CURRENT_USER, aKeyName, aKey, aHKLMOnly); case ERROR_FILE_NOT_FOUND: - if (aCreate) - result = ::RegCreateKey(HKEY_LOCAL_MACHINE, aKeyName, aKey); - rv = NS_ERROR_FILE_NOT_FOUND; - break; + rv = ::RegCreateKey(aStartKey, aKeyName, aKey); + if (rv != ERROR_SUCCESS) { + if (aHKLMOnly || aStartKey == HKEY_CURRENT_USER) { + // prevent infinite recursion on the second pass through here if + // ::RegCreateKey fails in the current user case. + return NS_ERROR_FILE_ACCESS_DENIED; + } + return OpenKeyForWriting(HKEY_CURRENT_USER, aKeyName, aKey, aHKLMOnly); + } } - return rv; + + return NS_OK; } /////////////////////////////////////////////////////////////////////////////// @@ -128,55 +145,69 @@ OpenKeyForWriting(const char* aKeyName, HKEY* aKey, PRBool aForAllUsers, PRBool // .htm .html .shtml .xht .xhtml // are mapped like so: // -// HKCU\SOFTWARE\Classes\.\ (default) REG_SZ FirefoxHTML +// HKCU\SOFTWARE\Classes\.\ (default) REG_SZ FirefoxHTML // // as aliases to the class: // // HKCU\SOFTWARE\Classes\FirefoxHTML\ -// DefaultIcon (default) REG_SZ ,1 -// shell\open\command (default) REG_SZ -url "%1" +// DefaultIcon (default) REG_SZ ,1 +// shell\open\command (default) REG_SZ -url "%1" -requestPending +// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,, +// shell\open\ddeexec NoActivateHandler REG_SZ +// \Application (default) REG_SZ Firefox +// \Topic (default) REG_SZ WWW_OpenURL +// +// - Windows Vista Protocol Handler +// +// HKCU\SOFTWARE\Classes\FirefoxURL\ (default) REG_SZ URL +// EditFlags REG_DWORD 2 +// FriendlyTypeName REG_SZ URL +// DefaultIcon (default) REG_SZ ,0 +// shell\open\command (default) REG_SZ -url "%1" -requestPending +// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,, +// shell\open\ddeexec NoActivateHandler REG_SZ +// \Application (default) REG_SZ Firefox +// \Topic (default) REG_SZ WWW_OpenURL // // - Protocol Mappings // ----------------- // The following protocols: -// HTTP, HTTPS, FTP, GOPHER, CHROME +// HTTP, HTTPS, FTP, GOPHER // are mapped like so: // -// HKCU\SOFTWARE\Classes\\ -// DefaultIcon (default) REG_SZ ,0 -// shell\open\command (default) REG_SZ -url "%1" -// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,, -// shell\open\ddeexec NoActivateHandler REG_SZ -// \application (default) REG_SZ Firefox -// \ifexec (default) REG_SZ ,,0,0,,,, -// \topic (default) REG_SZ WWW_OpenURL -// +// HKCU\SOFTWARE\Classes\\ +// DefaultIcon (default) REG_SZ ,0 +// shell\open\command (default) REG_SZ -url "%1" -requestPending +// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,, +// shell\open\ddeexec NoActivateHandler REG_SZ +// \Application (default) REG_SZ Firefox +// \Topic (default) REG_SZ WWW_OpenURL // -// - Windows XP Start Menu Browser -// ----------------------------- -// The following keys are set to make Firefox appear in the Windows XP -// Start Menu as the browser: +// - Windows Start Menu (Win2K SP2, 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\DefaultIcon (default) REG_SZ ,0 -// firefox.exe\shell\open\command (default) REG_SZ -// firefox.exe\shell\properties (default) REG_SZ Firefox &Options -// firefox.exe\shell\properties\command(default) REG_SZ -preferences -// -// - Uninstall Information -// --------------------- -// Every key that is set has the previous value stored in: -// -// HKCU\SOFTWARE\Mozilla\Desktop\ REG_SZ oldval -// -// If there is no previous value, an empty value is set to indicate that the -// key should be removed completely. +// HKCU\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\ +// (default) REG_SZ +// DefaultIcon (default) REG_SZ ,0 +// InstallInfo HideIconsCommand REG_SZ /HideShortcuts +// InstallInfo IconsVisible REG_DWORD 1 +// InstallInfo ReinstallCommand REG_SZ /SetAsDefaultAppGlobal +// InstallInfo ShowIconsCommand REG_SZ /ShowShortcuts +// shell\open\command (default) REG_SZ +// shell\properties (default) REG_SZ &Options +// shell\properties\command (default) REG_SZ -preferences +// shell\safemode (default) REG_SZ &Safe Mode +// shell\safemode\command (default) REG_SZ -safe-mode // -typedef enum { NO_SUBSTITUTION = 0x00, - PATH_SUBSTITUTION = 0x01, - EXE_SUBSTITUTION = 0x02, - NON_ESSENTIAL = 0x04} SettingFlags; +typedef enum { NO_SUBSTITUTION = 0x00, + APP_PATH_SUBSTITUTION = 0x01, + EXE_NAME_SUBSTITUTION = 0x02, + UNINST_PATH_SUBSTITUTION = 0x04, + HKLM_ONLY = 0x08, + NON_ESSENTIAL = 0x10 } SettingFlags; typedef struct { char* keyName; char* valueName; @@ -185,20 +216,24 @@ typedef struct { PRInt32 flags; } SETTING; +#define APP_REG_NAME L"Firefox" #define SMI "SOFTWARE\\Clients\\StartMenuInternet\\" #define CLS "SOFTWARE\\Classes\\" #define DI "\\DefaultIcon" +#define II "\\InstallInfo" #define SOP "\\shell\\open\\command" #define DDE "\\shell\\open\\ddeexec\\" #define DDE_NAME "Firefox" // This must be kept in sync with ID_DDE_APPLICATION_NAME as defined in splash.rc -#define APP_REG_NAME L"Firefox" #define DDE_COMMAND "\"%1\",,0,0,,,," -#define DDE_IFEXEC ",,0,0,,,," +// For the InstallInfo HideIconsCommand, ShowIconsCommand, and ReinstallCommand +// registry keys. This must be kept in sync with the uninstaller. +#define UNINSTALL_EXE "\\uninstall\\helper.exe" #define CLS_HTML "FirefoxHTML" +#define CLS_URL "FirefoxURL" #define VAL_URL_ICON "%APPPATH%,0" #define VAL_FILE_ICON "%APPPATH%,1" -#define VAL_OPEN "\"%APPPATH%\" -url \"%1\"" +#define VAL_OPEN "\"%APPPATH%\" -url \"%1\" -requestPending" #define MAKE_KEY_NAME1(PREFIX, MID) \ PREFIX MID @@ -210,12 +245,6 @@ typedef struct { PREFIX MID MID2 SUFFIX static SETTING gSettings[] = { - // Extension Manager Keys - { MAKE_KEY_NAME1(CLS, "MIME\\Database\\Content Type\\application/x-xpinstall;app=firefox"), - "Extension", - ".xpi", - NO_SUBSTITUTION | NON_ESSENTIAL }, - // File Extension Aliases { MAKE_KEY_NAME1(CLS, ".htm"), "", CLS_HTML, NO_SUBSTITUTION | NON_ESSENTIAL }, { MAKE_KEY_NAME1(CLS, ".html"), "", CLS_HTML, NO_SUBSTITUTION | NON_ESSENTIAL }, @@ -224,64 +253,72 @@ static SETTING gSettings[] = { { MAKE_KEY_NAME1(CLS, ".xhtml"), "", CLS_HTML, NO_SUBSTITUTION | NON_ESSENTIAL }, // File Extension Class - { MAKE_KEY_NAME2(CLS, CLS_HTML, DI), "", VAL_FILE_ICON, PATH_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME2(CLS, CLS_HTML, SOP), "", VAL_OPEN, PATH_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, CLS_HTML, DI), "", VAL_FILE_ICON, APP_PATH_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, CLS_HTML, SOP), "", VAL_OPEN, APP_PATH_SUBSTITUTION }, + + // Protocol Handler Class - for Vista and above + { MAKE_KEY_NAME2(CLS, CLS_URL, DI), "", VAL_URL_ICON, APP_PATH_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, CLS_URL, SOP), "", VAL_OPEN, APP_PATH_SUBSTITUTION }, // Protocol Handlers - { MAKE_KEY_NAME2(CLS, "HTTP", DI), "", VAL_URL_ICON, PATH_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "HTTP", SOP), "", VAL_OPEN, PATH_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "HTTPS", DI), "", VAL_URL_ICON, PATH_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "HTTPS", SOP), "", VAL_OPEN, PATH_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "FTP", DI), "", VAL_URL_ICON, PATH_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME2(CLS, "FTP", SOP), "", VAL_OPEN, PATH_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME2(CLS, "GOPHER", DI), "", VAL_URL_ICON, PATH_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME2(CLS, "GOPHER", SOP), "", VAL_OPEN, PATH_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME2(CLS, "CHROME", DI), "", VAL_URL_ICON, PATH_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME2(CLS, "CHROME", SOP), "", VAL_OPEN, PATH_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "HTTP", DI), "", VAL_URL_ICON, APP_PATH_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, "HTTP", SOP), "", VAL_OPEN, APP_PATH_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, "HTTPS", DI), "", VAL_URL_ICON, APP_PATH_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, "HTTPS", SOP), "", VAL_OPEN, APP_PATH_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, "FTP", DI), "", VAL_URL_ICON, APP_PATH_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "FTP", SOP), "", VAL_OPEN, APP_PATH_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "GOPHER", DI), "", VAL_URL_ICON, APP_PATH_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "GOPHER", SOP), "", VAL_OPEN, APP_PATH_SUBSTITUTION | NON_ESSENTIAL }, // DDE settings - { MAKE_KEY_NAME2(CLS, CLS_HTML, DDE), "", DDE_COMMAND, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, CLS_HTML, DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, CLS_HTML, DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, CLS_HTML, DDE, "ifexec"), "", DDE_IFEXEC, NO_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "HTTP", DDE), "", DDE_COMMAND, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "HTTP", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "HTTP", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "HTTP", DDE, "ifexec"), "", DDE_IFEXEC, NO_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "HTTPS", DDE), "", DDE_COMMAND, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "HTTPS", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "HTTPS", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "HTTPS", DDE, "ifexec"), "", DDE_IFEXEC, NO_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "FTP", DDE), "", DDE_COMMAND, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "FTP", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "FTP", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION }, - { MAKE_KEY_NAME3(CLS, "FTP", DDE, "ifexec"), "", DDE_IFEXEC, NO_SUBSTITUTION }, + { MAKE_KEY_NAME2(CLS, CLS_HTML, DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, CLS_HTML, DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, CLS_HTML, DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, CLS_URL, DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, CLS_URL, DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, CLS_URL, DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "HTTP", DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, "HTTP", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, "HTTP", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "HTTPS", DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, "HTTPS", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, "HTTPS", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(CLS, "FTP", DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, "FTP", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, + { MAKE_KEY_NAME3(CLS, "FTP", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, { MAKE_KEY_NAME2(CLS, "GOPHER", DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, { MAKE_KEY_NAME3(CLS, "GOPHER", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, { MAKE_KEY_NAME3(CLS, "GOPHER", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME3(CLS, "GOPHER", DDE, "ifexec"), "", DDE_IFEXEC, NO_SUBSTITUTION }, - { MAKE_KEY_NAME2(CLS, "CHROME", DDE), "", DDE_COMMAND, NO_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME3(CLS, "CHROME", DDE, "Application"), "", DDE_NAME, NO_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME3(CLS, "CHROME", DDE, "Topic"), "", "WWW_OpenURL", NO_SUBSTITUTION | NON_ESSENTIAL }, - { MAKE_KEY_NAME3(CLS, "CHROME", DDE, "ifexec"), "", DDE_IFEXEC, NO_SUBSTITUTION }, // Windows XP Start Menu { MAKE_KEY_NAME2(SMI, "%APPEXE%", DI), "", "%APPPATH%,0", - PATH_SUBSTITUTION | EXE_SUBSTITUTION | NON_ESSENTIAL }, + APP_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(SMI, "%APPEXE%", II), + "HideIconsCommand", + "\"%UNINSTPATH%\" /HideShortcuts", + UNINST_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(SMI, "%APPEXE%", II), + "ReinstallCommand", + "\"%UNINSTPATH%\" /SetAsDefaultAppGlobal", + UNINST_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL }, + { MAKE_KEY_NAME2(SMI, "%APPEXE%", II), + "ShowIconsCommand", + "\"%UNINSTPATH%\" /ShowShortcuts", + UNINST_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL }, { MAKE_KEY_NAME2(SMI, "%APPEXE%", SOP), "", "%APPPATH%", - PATH_SUBSTITUTION | EXE_SUBSTITUTION | NON_ESSENTIAL }, + APP_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL }, { MAKE_KEY_NAME1(SMI, "%APPEXE%\\shell\\properties\\command"), "", "\"%APPPATH%\" -preferences", - PATH_SUBSTITUTION | EXE_SUBSTITUTION | NON_ESSENTIAL }, + APP_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL }, { MAKE_KEY_NAME1(SMI, "%APPEXE%\\shell\\safemode\\command"), "", "\"%APPPATH%\" -safe-mode", - PATH_SUBSTITUTION | EXE_SUBSTITUTION | NON_ESSENTIAL } + APP_PATH_SUBSTITUTION | EXE_NAME_SUBSTITUTION | HKLM_ONLY | NON_ESSENTIAL } // These values must be set by hand, since they contain localized strings. // firefox.exe\shell\properties (default) REG_SZ Firefox &Options @@ -390,6 +427,12 @@ nsWindowsShellService::SetDefaultBrowserVista() NS_IMETHODIMP nsWindowsShellService::IsDefaultBrowser(PRBool aStartupCheck, PRBool* aIsDefaultBrowser) { + // To support side by side installs on Vista we also need to check if the + // FirefoxHTML and FirefoxURL registry keys in HKLM / HKCU point to our + // install location. If the HKLM keys point to this install location we have + // to verify that the keys don't exist in HKCU and remove them if the app is + // then set as default. If the HKLM keys don't point to this install location + // then we have to add these keys in HKCU to over-ride the HKLM keys. if (IsDefaultBrowserVista(aStartupCheck, aIsDefaultBrowser)) return NS_OK; @@ -433,7 +476,7 @@ nsWindowsShellService::IsDefaultBrowser(PRBool aStartupCheck, PRBool* aIsDefault nsCAutoString dataLongPath(settings->valueData); nsCAutoString dataShortPath(settings->valueData); nsCAutoString key(settings->keyName); - if (settings->flags & PATH_SUBSTITUTION) { + if (settings->flags & APP_PATH_SUBSTITUTION) { PRInt32 offset = dataLongPath.Find("%APPPATH%"); dataLongPath.Replace(offset, 9, appLongPath); // Remove the quotes around %APPPATH% in VAL_OPEN for short paths @@ -443,7 +486,7 @@ nsWindowsShellService::IsDefaultBrowser(PRBool aStartupCheck, PRBool* aIsDefault else dataShortPath.Replace(offset, 9, appShortPath); } - if (settings->flags & EXE_SUBSTITUTION) { + if (settings->flags & EXE_NAME_SUBSTITUTION) { PRInt32 offset = key.Find("%APPEXE%"); key.Replace(offset, 8, exeName); } @@ -502,26 +545,39 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs return rv; ToUpperCase(exeName); + nsCOMPtr appDir; + rv = lf->GetParent(getter_AddRefs(appDir)); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString parentPath; + appDir->GetNativePath(parentPath); + + nsCAutoString uninstLongPath(parentPath.get()); + uninstLongPath.Append(UNINSTALL_EXE); + for (settings = gSettings; settings < end; ++settings) { nsCAutoString dataLongPath(settings->valueData); nsCAutoString key(settings->keyName); - if (settings->flags & PATH_SUBSTITUTION) { + if (settings->flags & APP_PATH_SUBSTITUTION) { PRInt32 offset = dataLongPath.Find("%APPPATH%"); dataLongPath.Replace(offset, 9, appLongPath); } - if (settings->flags & EXE_SUBSTITUTION) { + if (settings->flags & UNINST_PATH_SUBSTITUTION) { + PRInt32 offset = dataLongPath.Find("%UNINSTPATH%"); + dataLongPath.Replace(offset, 12, uninstLongPath); + } + if (settings->flags & EXE_NAME_SUBSTITUTION) { PRInt32 offset = key.Find("%APPEXE%"); key.Replace(offset, 8, exeName); } - PRBool replaceExisting = aClaimAllTypes ? PR_TRUE : !(settings->flags & NON_ESSENTIAL); SetRegKey(key.get(), settings->valueName, dataLongPath.get(), - replaceExisting, aForAllUsers); + (settings->flags & HKLM_ONLY)); } // Select the Default Browser for the Windows XP Start Menu - SetRegKey(NS_LITERAL_CSTRING(SMI).get(), "", exeName.get(), aClaimAllTypes, - aForAllUsers); + SetRegKey(NS_LITERAL_CSTRING(SMI).get(), "", exeName.get(), PR_TRUE); nsCOMPtr bundleService(do_GetService("@mozilla.org/intl/stringbundle;1")); if (!bundleService) @@ -545,8 +601,7 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs nsCAutoString key1(NS_LITERAL_CSTRING(SMI)); key1.Append(exeName); key1.Append("\\"); - SetRegKey(key1.get(), "", nativeFullName.get(), aClaimAllTypes, - aForAllUsers); + SetRegKey(key1.get(), "", nativeFullName.get(), PR_TRUE); // Set the Options and Safe Mode start menu context menu item labels nsCAutoString optionsKey(SMI); @@ -577,13 +632,11 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs // For the now, we use 'A' APIs (see bug 240272, 239279) NS_UTF16ToCString(optionsTitle, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, nativeTitle); - SetRegKey(optionsKey.get(), "", nativeTitle.get(), aClaimAllTypes, - aForAllUsers); + SetRegKey(optionsKey.get(), "", nativeTitle.get(), PR_TRUE); // For the now, we use 'A' APIs (see bug 240272, 239279) NS_UTF16ToCString(safeModeTitle, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, nativeTitle); - SetRegKey(safeModeKey.get(), "", nativeTitle.get(), aClaimAllTypes, - aForAllUsers); + SetRegKey(safeModeKey.get(), "", nativeTitle.get(), PR_TRUE); // Refresh the Shell SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); @@ -592,19 +645,14 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs void nsWindowsShellService::SetRegKey(const char* aKeyName, const char* aValueName, - const char* aValue, PRBool aReplaceExisting, - PRBool aForAllUsers) + const char* aValue, PRBool aHKLMOnly) { char buf[MAX_BUF]; DWORD len = sizeof buf; HKEY theKey; - nsresult rv = OpenKeyForWriting(aKeyName, &theKey, aForAllUsers, PR_TRUE); - if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) return; - - // If we're not allowed to replace an existing key, and one exists (i.e. the - // result isn't ERROR_FILE_NOT_FOUND, then just return now. - if (!aReplaceExisting && rv != NS_ERROR_FILE_NOT_FOUND) + nsresult rv = OpenKeyForWriting(HKEY_LOCAL_MACHINE, aKeyName, &theKey, aHKLMOnly); + if (NS_FAILED(rv)) return; // Get the old value diff --git a/mozilla/browser/components/shell/src/nsWindowsShellService.h b/mozilla/browser/components/shell/src/nsWindowsShellService.h index 9c6338b0805..9b481524a58 100644 --- a/mozilla/browser/components/shell/src/nsWindowsShellService.h +++ b/mozilla/browser/components/shell/src/nsWindowsShellService.h @@ -61,8 +61,7 @@ protected: PRBool GetMailAccountKey(HKEY* aResult); void SetRegKey(const char* aKeyName, const char* aValueName, - const char* aValue, PRBool aReplaceExisting, - PRBool aForAllUsers); + const char* aValue, PRBool aHKLMOnly); private: PRBool mCheckedThisSession; diff --git a/mozilla/browser/installer/removed-files.in b/mozilla/browser/installer/removed-files.in index 43886f6ad33..4f9a0b4fe15 100644 --- a/mozilla/browser/installer/removed-files.in +++ b/mozilla/browser/installer/removed-files.in @@ -68,5 +68,7 @@ extensions/inspector@mozilla.org/components/inspector.xpt extensions/inspector@mozilla.org/components/@DLL_PREFIX@inspector@DLL_SUFFIX@ uninstall/UninstallFirefox.exe uninstall/UninstallDeerPark.exe +uninstall/uninst.exe +uninstall/uninstall.exe components/myspell/en-US.dic components/myspell/en-US.aff diff --git a/mozilla/browser/installer/windows/Makefile.in b/mozilla/browser/installer/windows/Makefile.in index 4efde1d22d7..7f1a9e7f4e4 100644 --- a/mozilla/browser/installer/windows/Makefile.in +++ b/mozilla/browser/installer/windows/Makefile.in @@ -56,6 +56,7 @@ INSTALLER_FILES = \ app.tag \ nsis/installer.nsi \ nsis/uninstaller.nsi \ + nsis/shared.nsh \ $(NULL) BRANDING_FILES = \ diff --git a/mozilla/browser/installer/windows/nsis/defines.nsi.in b/mozilla/browser/installer/windows/nsis/defines.nsi.in index 49dafe380fe..151fafbf28b 100755 --- a/mozilla/browser/installer/windows/nsis/defines.nsi.in +++ b/mozilla/browser/installer/windows/nsis/defines.nsi.in @@ -9,3 +9,4 @@ !define FileMainEXE "@MOZ_APP_NAME@.exe" !define WindowClass "FirefoxMessageWindow" !define DDEApplication "Firefox" +!define AppRegName "Firefox" diff --git a/mozilla/browser/installer/windows/nsis/installer.nsi b/mozilla/browser/installer/windows/nsis/installer.nsi index 5398ba0f349..5792e476aac 100755 --- a/mozilla/browser/installer/windows/nsis/installer.nsi +++ b/mozilla/browser/installer/windows/nsis/installer.nsi @@ -83,7 +83,6 @@ Var fhUninstallLog !insertmacro GetOptions !insertmacro GetRoot !insertmacro DriveSpace -!insertmacro GetParent ; NSIS provided macros that we have overridden !include overrides.nsh @@ -97,6 +96,8 @@ Var fhUninstallLog !include locales.nsi !include version.nsh +VIAddVersionKey "FileDescription" "${BrandShortName} Installer" + !insertmacro RegCleanMain !insertmacro RegCleanUninstall !insertmacro CloseApp @@ -105,9 +106,10 @@ Var fhUninstallLog !insertmacro CreateRegKey !insertmacro CanWriteToInstallDir !insertmacro CheckDiskSpace +!insertmacro AddHandlerValues !insertmacro DisplayCopyErrMsg -!insertmacro GetExistingInstallPath -!insertmacro IsVista + +!include shared.nsh Name "${BrandFullName}" OutFile "setup.exe" @@ -432,240 +434,35 @@ Section "-Application" Section1 ; 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} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Main" - ${WriteRegStr2} $TmpVal "$0" "Install Directory" "$INSTDIR" 0 - ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$INSTDIR\${FileMainEXE}" 0 - ${WriteRegStr2} $TmpVal "$0" "Program Folder Path" "$SMPROGRAMS\$StartMenuDir" 0 - ${WriteRegDWORD2} $TmpVal "$0" "Create Quick Launch Shortcut" $AddQuickLaunchSC 0 - ${WriteRegDWORD2} $TmpVal "$0" "Create Desktop Shortcut" $AddDesktopSC 0 + ; XXXrstrong - this should be set in shared.nsh along with "Create Quick + ; Launch Shortcut" and Create Desktop Shortcut. + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Uninstall" ${WriteRegDWORD2} $TmpVal "$0" "Create Start Menu Shortcut" $AddStartMenuSC 0 - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Uninstall" - ${WriteRegStr2} $TmpVal "$0" "Uninstall Log Folder" "$INSTDIR\uninstall" 0 - ${WriteRegStr2} $TmpVal "$0" "Description" "${BrandFullNameInternal} (${AppVersion})" 0 + ${FixFileKeys} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})" - ${WriteRegStr2} $TmpVal "$0" "" "${AppVersion} (${AB_CD})" 0 + ${FixProtocolKeys} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}\bin" - ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$INSTDIR\${FileMainEXE}" 0 + ; The following keys should only be set if we can write to HKLM + ${If} $TmpVal == "HKLM" + ; Uninstall keys can only exist under HKLM on some versions of windows. + ${SetUninstallKeys} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}\extensions" - ${WriteRegStr2} $TmpVal "$0" "Components" "$INSTDIR\components" 0 - ${WriteRegStr2} $TmpVal "$0" "Plugins" "$INSTDIR\plugins" 0 + ; Set the Start Menu Internet and Vista Registered App HKLM registry keys. + ${SetStartMenuInternet} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}" - ${WriteRegStr2} $TmpVal "$0" "GeckoVer" "${GREVersion}" 0 - - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}" - ${WriteRegStr2} $TmpVal "$0" "" "${GREVersion}" 0 - ${WriteRegStr2} $TmpVal "$0" "CurrentVersion" "${AppVersion} (${AB_CD})" 0 - - ; XXXrstrong - there are several values that will be overwritten by and - ; overwrite other installs of the same application. - ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 - StrCpy $0 "Software\Clients\StartMenuInternet\$R9" - ${WriteRegStr2} $TmpVal "$0" "" "${BrandShortName}" 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\DefaultIcon" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\",0" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 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 - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo" - StrCpy $1 "$\"$INSTDIR\uninstall\uninst.exe$\" /HideShortcuts" - ${WriteRegStr2} $TmpVal "$0" "HideIconsCommand" "$1" 0 - ${WriteRegDWORD2} $TmpVal "$0" "IconsVisible" 1 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\" -silent -setDefaultBrowser" - ${WriteRegStr2} $TmpVal "$0" "ReinstallCommand" "$1" 0 - StrCpy $1 "$\"$INSTDIR\uninstall\uninst.exe$\" /ShowShortcuts" - ${WriteRegStr2} $TmpVal "$0" "ShowIconsCommand" "$1" 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\shell\open\command" - ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\shell\properties" - ${WriteRegStr2} $TmpVal "$0" "" "$(OPTIONS)" 0 - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\shell\properties\command" - ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE} -preferences" 0 - - - - ${IsVista} $R9 - ${If} $R9 == "true" - ; For Vista these keys and name / value pairs may need to be created during - ; install. - ReadRegStr $0 HKLM "Software\Classes\.shtml" "Content Type" - ${If} $0 == "" - StrCpy $0 "Software\Classes\.shtml" - ${WriteRegStr2} $TmpVal "$0" "" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" "Content Type" "text/html" 0 - ${WriteRegStr2} $TmpVal "$0" "PerceivedType" "text" 0 + ; If we are writing to HKLM and create the quick launch and the desktop + ; shortcuts set IconsVisible to 1 otherwise to 0. + ${If} $AddQuickLaunchSC == 1 + ${OrIf} $AddDesktopSC == 1 + ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 + StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo" + WriteRegDWORD HKLM "$0" "IconsVisible" 1 + ${Else} + WriteRegDWORD HKLM "$0" "IconsVisible" 0 ${EndIf} - - ReadRegStr $0 HKLM "Software\Classes\.xht" "Content Type" - ${If} $0 == "" - StrCpy $0 "Software\Classes\.xht" - ${WriteRegStr2} $TmpVal "$0" "" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" "Content Type" "application/xhtml+xml" 0 - ${EndIf} - - ReadRegStr $0 HKLM "Software\Classes\.xhtml" "Content Type" - ${If} $0 == "" - StrCpy $0 "Software\Classes\.xhtml" - ${WriteRegStr2} $TmpVal "$0" "" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" "Content Type" "application/xhtml+xml" 0 - ${EndIf} - - ReadRegStr $0 HKLM "Software\Classes\gopher\shell\open\command" "" - ${If} $0 == "" - StrCpy $0 "Software\Classes\gopher" - ${WriteRegStr2} $TmpVal "$0" "" "URL:Gopher Protocol" 0 - ${WriteRegStr2} $TmpVal "$0" "URL Protocol" "" 0 - ${WriteRegDWORD2} $TmpVal "$0" "EditFlags" 2 0 - - StrCpy $0 "Software\Classes\gopher\DefaultIcon" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\",0" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\gopher\shell\open\command" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\" -url $\"%1$\"" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\gopher\shell\open\ddeexec" - StrCpy $1 "$\"%1$\",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - ${WriteRegStr2} $TmpVal "$0" "NoActivateHandler" "" 0 - - StrCpy $0 "Software\Classes\gopher\shell\open\ddeexec\Application" - ${WriteRegStr2} $TmpVal "$0" "" "${DDEApplication}" 0 - - StrCpy $0 "Software\Classes\gopher\shell\open\ddeexec\ifexec" - StrCpy $1 ",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\gopher\shell\open\ddeexec\Topic" - ${WriteRegStr2} $TmpVal "$0" "" "WWW_OpenURL" 0 - ${EndIf} - - ; Only create the key and its children if it doesn't exist - ReadRegStr $0 HKLM "Software\Classes\chrome\shell\open\command" "" - ${If} $0 == "" - StrCpy $0 "Software\Classes\chrome" - ${WriteRegStr2} $TmpVal "$0" "" "URL:Chrome Protocol" 0 - ${WriteRegStr2} $TmpVal "$0" "URL Protocol" "" 0 - ${WriteRegDWORD2} $TmpVal "$0" "EditFlags" 2 0 - - StrCpy $0 "Software\Classes\chrome\DefaultIcon" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\",0" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\chrome\shell\open\command" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\" -url $\"%1$\"" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\chrome\shell\open\ddeexec" - StrCpy $1 "$\"%1$\",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - ${WriteRegStr2} $TmpVal "$0" "NoActivateHandler" "" 0 - - StrCpy $0 "Software\Classes\chrome\shell\open\ddeexec\Application" - ${WriteRegStr2} $TmpVal "$0" "" "${DDEApplication}" 0 - - StrCpy $0 "Software\Classes\chrome\shell\open\ddeexec\ifexec" - StrCpy $1 ",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\chrome\shell\open\ddeexec\Topic" - ${WriteRegStr2} $TmpVal "$0" "" "WWW_OpenURL" 0 - ${EndIf} - - ; Always set the file and protocol handlers since they may specify a - ; different path and the path is used by Vista when setting associations. - StrCpy $0 "Software\Classes\FirefoxURL" - ${WriteRegStr2} $TmpVal "$0" "" "Firefox URL" 0 - ${WriteRegStr2} $TmpVal "$0" "FriendlyTypeName" "Firefox URL" 0 - ${WriteRegStr2} $TmpVal "$0" "URL Protocol" "" 0 - ${WriteRegDWORD2} $TmpVal "$0" "EditFlags" 2 0 - - StrCpy $0 "Software\Classes\FirefoxURL\DefaultIcon" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\",0" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\FirefoxURL\shell\open\command" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\" -url $\"%1$\"" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\FirefoxURL\shell\open\ddeexec" - StrCpy $1 "$\"%1$\",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - ${WriteRegStr2} $TmpVal "$0" "NoActivateHandler" "" 0 - - StrCpy $0 "Software\Classes\FirefoxURL\shell\open\ddeexec\Application" - ${WriteRegStr2} $TmpVal "$0" "" "${DDEApplication}" 0 - - StrCpy $0 "Software\Classes\FirefoxURL\shell\open\ddeexec\ifexec" - StrCpy $1 ",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\FirefoxURL\shell\open\ddeexec\Topic" - ${WriteRegStr2} $TmpVal "$0" "" "WWW_OpenURL" 0 - - StrCpy $0 "Software\Classes\FirefoxHTML\DefaultIcon" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\",1" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\FirefoxHTML\shell\open\command" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\" -url $\"%1$\"" - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\FirefoxHTML\shell\open\ddeexec" - StrCpy $1 "$\"%1$\",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - ${WriteRegStr2} $TmpVal "$0" "NoActivateHandler" "" 0 - - StrCpy $0 "Software\Classes\FirefoxHTML\shell\open\ddeexec\Application" - ${WriteRegStr2} $TmpVal "$0" "" "${DDEApplication}" 0 - - StrCpy $0 "Software\Classes\FirefoxHTML\shell\open\ddeexec\ifexec" - StrCpy $1 ",,0,0,,,," - ${WriteRegStr2} $TmpVal "$0" "" "$1" 0 - - StrCpy $0 "Software\Classes\FirefoxHTML\shell\open\ddeexec\Topic" - ${WriteRegStr2} $TmpVal "$0" "" "WWW_OpenURL" 0 - - ; Vista Registered Application - ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 - StrCpy $0 "Software\RegisteredApplications" - StrCpy $1 "Software\Clients\StartMenuInternet\$R9\Capabilities" - ${WriteRegStr2} $TmpVal "$0" "${DDEApplication}" "$1" 0 - - ; Vista Capabilities registry keys - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\Capabilities" - StrCpy $1 "$\"$INSTDIR\${FileMainEXE}$\",0" - ${WriteRegStr2} $TmpVal "$0" "ApplicationDescription" "$(REG_APP_DESC)" 0 - ${WriteRegStr2} $TmpVal "$0" "ApplicationIcon" "$1" 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\Capabilities\FileAssociations" - ${WriteRegStr2} $TmpVal "$0" ".htm" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" ".html" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" ".shtml" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" ".xht" "FirefoxHTML" 0 - ${WriteRegStr2} $TmpVal "$0" ".xhtml" "FirefoxHTML" 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\Capabilities\StartMenu" - ${WriteRegStr2} $TmpVal "$0" "StartMenuInternet" "$R9" 0 - - StrCpy $0 "Software\Clients\StartMenuInternet\$R9\Capabilities\URLAssociations" - ${WriteRegStr2} $TmpVal "$0" "chrome" "FirefoxURL" 0 - ${WriteRegStr2} $TmpVal "$0" "ftp" "FirefoxURL" 0 - ${WriteRegStr2} $TmpVal "$0" "gopher" "FirefoxURL" 0 - ${WriteRegStr2} $TmpVal "$0" "http" "FirefoxURL" 0 - ${WriteRegStr2} $TmpVal "$0" "https" "FirefoxURL" 0 ${EndIf} ; These need special handling on uninstall since they may be overwritten by @@ -674,27 +471,9 @@ Section "-Application" Section1 ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0 ${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0 - StrCpy $0 "Software\Classes\MIME\Database\Content Type\application/x-xpinstall;app=firefox" - ${WriteRegStr2} $TmpVal "$0" "Extension" ".xpi" 0 - StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\$R9" ${CreateRegKey} "$TmpVal" "$0" 0 - ; Write the uninstall registry keys - StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} (${AppVersion})" - StrCpy $1 "$INSTDIR\uninstall\uninst.exe" - - ${WriteRegStr2} $TmpVal "$0" "Comments" "${BrandFullNameInternal}" 0 - ${WriteRegStr2} $TmpVal "$0" "DisplayIcon" "$INSTDIR\${FileMainEXE},0" 0 - ${WriteRegStr2} $TmpVal "$0" "DisplayName" "${BrandFullNameInternal} (${AppVersion})" 0 - ${WriteRegStr2} $TmpVal "$0" "DisplayVersion" "${AppVersion} (${AB_CD})" 0 - ${WriteRegStr2} $TmpVal "$0" "InstallLocation" "$INSTDIR" 0 - ${WriteRegStr2} $TmpVal "$0" "Publisher" "Mozilla" 0 - ${WriteRegStr2} $TmpVal "$0" "UninstallString" "$1" 0 - ${WriteRegStr2} $TmpVal "$0" "URLInfoAbout" "${URLInfoAbout}" 0 - ${WriteRegStr2} $TmpVal "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0 - ${WriteRegDWORD2} $TmpVal "$0" "NoModify" 1 0 - ${WriteRegDWORD2} $TmpVal "$0" "NoRepair" 1 0 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ; Create Start Menu shortcuts @@ -905,7 +684,7 @@ Function CopyFile ; If the file is installed into the installation directory remove the ; installation directory's path from the file path when writing to the ; uninstall.log so it will be a relative path. This allows the same - ; uninst.exe to be used with zip builds if we supply an uninstall.log. + ; helper.exe to be used with zip builds if we supply an uninstall.log. ${WordReplace} "$R1$R3\$R7" "$INSTDIR" "" "+" $R3 ${LogUninstall} "File: $R3" ${EndIf} @@ -1067,22 +846,6 @@ Function leaveComponents FunctionEnd Function preDirectory - ${IsVista} $R9 - ${If} $R9 == "true" - SetShellVarContext all ; Set SHCTX to HKLM - ${GetExistingInstallPath} "Software\Mozilla" $R9 - ${If} $R9 != "false" - StrCpy $INSTDIR "$R9" - ${CheckDiskSpace} $R9 - ${If} $R9 == "true" - ${CanWriteToInstallDir} $R9 - ${If} $R9 == "true" - Abort - ${EndIf} - ${EndIf} - ${EndIf} - ${EndIf} - ${If} $InstallType != 4 ${CheckDiskSpace} $R9 ${If} $R9 != "false" diff --git a/mozilla/browser/installer/windows/nsis/shared.nsh b/mozilla/browser/installer/windows/nsis/shared.nsh new file mode 100755 index 00000000000..60f78ac616d --- /dev/null +++ b/mozilla/browser/installer/windows/nsis/shared.nsh @@ -0,0 +1,373 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Mozilla Installer code. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2006 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Strong +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +!macro PostUpdate + SetShellVarContext all + ${SetStartMenuInternet} + + ; Remove registry entries for non-existent apps and for apps that point to our + ; install location in the Software\Mozilla key. + SetShellVarContext current ; Set SHCTX to HKCU + ${RegCleanMain} "Software\Mozilla" + SetShellVarContext all ; Set SHCTX to HKLM + ${RegCleanMain} "Software\Mozilla" + + ; Remove uninstall entries that point to our install location + ${RegCleanUninstall} + + ; Add Software\Mozilla\ registry entries + ${SetAppKeys} + + ${SetUninstallKeys} + + ${FixFileKeys} + + ${FixProtocolKeys} + +!macroend +!define PostUpdate "!insertmacro PostUpdate" + +!macro SetAsDefaultAppUser + SetShellVarContext current + ${SetHandlers} +!macroend +!define SetAsDefaultAppUser "!insertmacro SetAsDefaultAppUser" + +!macro SetAsDefaultAppGlobal + SetShellVarContext all + ${SetHandlers} + ${SetStartMenuInternet} + WriteRegStr HKLM "Software\Clients\StartMenuInternet" "" "$R9" + ${ShowShortcuts} +!macroend +!define SetAsDefaultAppGlobal "!insertmacro SetAsDefaultAppGlobal" + +!macro HideShortcuts + ${StrFilter} "${FileMainEXE}" "+" "" "" $0 + StrCpy $R1 "Software\Clients\StartMenuInternet\$0\InstallInfo" + WriteRegDWORD HKLM $R1 "IconsVisible" 0 + SetShellVarContext all ; Set $DESKTOP to All Users + ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + SetShellVarContext current ; Set $DESKTOP to the current user's desktop + ${EndUnless} + + ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + ShellLink::GetShortCutArgs "$DESKTOP\${BrandFullName}.lnk" + Pop $0 + ${If} $0 == "" + ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk" + Pop $0 + ; Needs to handle short paths + ${If} $0 == "$INSTDIR\${FileMainEXE}" + Delete "$DESKTOP\${BrandFullName}.lnk" + ${EndIf} + ${EndIf} + ${EndIf} + + ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" + ShellLink::GetShortCutArgs "$QUICKLAUNCH\${BrandFullName}.lnk" + Pop $0 + ${If} $0 == "" + ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandFullName}.lnk" + Pop $0 + ; Needs to handle short paths + ${If} $0 == "$INSTDIR\${FileMainEXE}" + Delete "$QUICKLAUNCH\${BrandFullName}.lnk" + ${EndIf} + ${EndIf} + ${EndIf} +!macroend +!define HideShortcuts "!insertmacro HideShortcuts" + +!macro ShowShortcuts + ${StrFilter} "${FileMainEXE}" "+" "" "" $0 + StrCpy $R1 "Software\Clients\StartMenuInternet\$0\InstallInfo" + WriteRegDWORD HKLM $R1 "IconsVisible" 1 + SetShellVarContext all ; Set $DESKTOP to All Users + ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" "" "$INSTDIR\${FileMainEXE}" 0 + ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR" + ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + SetShellVarContext current ; Set $DESKTOP to the current user's desktop + ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" "" "$INSTDIR\${FileMainEXE}" 0 + ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR" + ${EndUnless} + ${EndUnless} + ${EndUnless} + ${Unless} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" + CreateShortCut "$QUICKLAUNCH\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" "" "$INSTDIR\${FileMainEXE}" 0 + ShellLink::SetShortCutWorkingDirectory "$QUICKLAUNCH\${BrandFullName}.lnk" "$INSTDIR" + ${EndUnless} +!macroend +!define ShowShortcuts "!insertmacro ShowShortcuts" + +!macro SetHandlers + GetFullPathName $8 "$INSTDIR\${FileMainEXE}" + + StrCpy $0 "SOFTWARE\Classes" + StrCpy $2 "$\"$8$\" -url $\"%1$\" -requestPending" + + ; Associate the file handlers with FirefoxHTML + WriteRegStr SHCTX "$0\.htm" "" "FirefoxHTML" + WriteRegStr SHCTX "$0\.html" "" "FirefoxHTML" + WriteRegStr SHCTX "$0\.shtml" "" "FirefoxHTML" + WriteRegStr SHCTX "$0\.xht" "" "FirefoxHTML" + WriteRegStr SHCTX "$0\.xhtml" "" "FirefoxHTML" + + ; An empty string is used for the 5th param because FirefoxHTML is not a + ; protocol handler + ${AddHandlerValues} "$0\FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" "true" + + ${AddHandlerValues} "$0\FirefoxURL" "$2" "$8,0" "${AppRegName} URL" "true" "true" + ${AddHandlerValues} "$0\gopher" "$2" "$8,0" "URL:Gopher Protocol" "true" "true" + + ; An empty string is used for the 4th & 5th params because the following + ; protocol handlers already have a display name and additional keys required + ; for a protocol handler. + ${AddHandlerValues} "$0\ftp" "$2" "$8,0" "" "" "true" + ${AddHandlerValues} "$0\http" "$2" "$8,0" "" "" "true" + ${AddHandlerValues} "$0\https" "$2" "$8,0" "" "" "true" +!macroend +!define SetHandlers "!insertmacro SetHandlers" + +; XXXrstrong - there are several values that will be overwritten by and +; overwrite other installs of the same application. +!macro SetStartMenuInternet + GetFullPathName $8 "$INSTDIR\${FileMainEXE}" + GetFullPathName $7 "$INSTDIR\uninstall\helper.exe" + + ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 + + StrCpy $0 "Software\Clients\StartMenuInternet\$R9" + ; Remove existing keys so we only have our settings + DeleteRegKey HKLM "$0" + WriteRegStr HKLM "$0" "" "${BrandFullName}" + + WriteRegStr HKLM "$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 HKLM "$0\InstallInfo" "HideIconsCommand" "$\"$7$\" /HideShortcuts" + WriteRegStr HKLM "$0\InstallInfo" "ShowIconsCommand" "$\"$7$\" /ShowShortcuts" + WriteRegStr HKLM "$0\InstallInfo" "ReinstallCommand" "$\"$7$\" /SetAsDefaultAppGlobal" + + WriteRegStr HKLM "$0\shell\open\command" "" "$8" + + WriteRegStr HKLM "$0\shell\properties" "" "$(CONTEXT_OPTIONS)" + WriteRegStr HKLM "$0\shell\properties\command" "" "$\"$8$\" -preferences" + + WriteRegStr HKLM "$0\shell\safemode" "" "$(CONTEXT_SAFE_MODE)" + WriteRegStr HKLM "$0\shell\safemode\command" "" "$\"$8$\" -safemode" + + ; Vista Capabilities registry keys + WriteRegStr HKLM "$0\Capabilities" "ApplicationDescription" "$(REG_APP_DESC)" + WriteRegStr HKLM "$0\Capabilities" "ApplicationIcon" "$8,0" + WriteRegStr HKLM "$0\Capabilities" "ApplicationName" "${BrandShortName}" + + WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".htm" "FirefoxHTML" + WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".html" "FirefoxHTML" + WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".shtml" "FirefoxHTML" + WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".xht" "FirefoxHTML" + WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".xhtml" "FirefoxHTML" + + WriteRegStr HKLM "$0\Capabilities\StartMenu" "StartMenuInternet" "$R9" + + WriteRegStr HKLM "$0\Capabilities\URLAssociations" "ftp" "FirefoxURL" + WriteRegStr HKLM "$0\Capabilities\URLAssociations" "gopher" "FirefoxURL" + WriteRegStr HKLM "$0\Capabilities\URLAssociations" "http" "FirefoxURL" + WriteRegStr HKLM "$0\Capabilities\URLAssociations" "https" "FirefoxURL" + + ; Vista Registered Application + WriteRegStr HKLM "Software\RegisteredApplications" "${AppRegName}" "$0\Capabilities" +!macroend +!define SetStartMenuInternet "!insertmacro SetStartMenuInternet" + +!macro SetAppKeys + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Main" + ${WriteRegStr2} $TmpVal "$0" "Install Directory" "$INSTDIR" 0 + ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$INSTDIR\${FileMainEXE}" 0 + ${WriteRegStr2} $TmpVal "$0" "Program Folder Path" "$SMPROGRAMS\$StartMenuDir" 0 + + SetShellVarContext all ; Set $DESKTOP to All Users + ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + SetShellVarContext current ; Set $DESKTOP to the current user's desktop + ${EndUnless} + + ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + ShellLink::GetShortCutArgs "$DESKTOP\${BrandFullName}.lnk" + Pop $1 + ${If} $1 == "" + ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk" + Pop $1 + ; Needs to handle short paths + ${If} $1 == "$INSTDIR\${FileMainEXE}" + ${WriteRegDWORD2} $TmpVal "$0" "Create Desktop Shortcut" 1 0 + ${Else} + ${WriteRegDWORD2} $TmpVal "$0" "Create Desktop Shortcut" 0 0 + ${EndIf} + ${EndIf} + ${EndIf} + + ; XXXrstrong - need a cleaner way to prevent unsetting SHCTX from HKLM when + ; trying to find the desktop shortcut. + ${If} $TmpVal == "HKCU" + SetShellVarContext current + ${Else} + SetShellVarContext all + ${EndIf} + + ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" + ShellLink::GetShortCutArgs "$QUICKLAUNCH\${BrandFullName}.lnk" + Pop $1 + ${If} $1 == "" + ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandFullName}.lnk" + Pop $1 + ; Needs to handle short paths + ${If} $1 == "$INSTDIR\${FileMainEXE}" + ${WriteRegDWORD2} $TmpVal "$0" "Create Quick Launch Shortcut" 1 0 + ${Else} + ${WriteRegDWORD2} $TmpVal "$0" "Create Quick Launch Shortcut" 0 0 + ${EndIf} + ${EndIf} + ${EndIf} + ; XXXrstrong - "Create Start Menu Shortcut" and "Start Menu Folder" are only + ; set in the installer and should also be set here for software update. + + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Uninstall" + ${WriteRegStr2} $TmpVal "$0" "Uninstall Log Folder" "$INSTDIR\uninstall" 0 + ${WriteRegStr2} $TmpVal "$0" "Description" "${BrandFullNameInternal} (${AppVersion})" 0 + + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})" + ${WriteRegStr2} $TmpVal "$0" "" "${AppVersion} (${AB_CD})" 0 + + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}\bin" + ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$INSTDIR\${FileMainEXE}" 0 + + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}\extensions" + ${WriteRegStr2} $TmpVal "$0" "Components" "$INSTDIR\components" 0 + ${WriteRegStr2} $TmpVal "$0" "Plugins" "$INSTDIR\plugins" 0 + + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}" + ${WriteRegStr2} $TmpVal "$0" "GeckoVer" "${GREVersion}" 0 + + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}" + ${WriteRegStr2} $TmpVal "$0" "" "${GREVersion}" 0 + ${WriteRegStr2} $TmpVal "$0" "CurrentVersion" "${AppVersion} (${AB_CD})" 0 +!macroend +!define SetAppKeys "!insertmacro SetAppKeys" + +!macro SetUninstallKeys + ; Write the uninstall registry keys + StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} (${AppVersion})" + GetFullPathName $8 "$INSTDIR\${FileMainEXE}" + GetFullPathName $7 "$INSTDIR\uninstall\helper.exe" + + ${WriteRegStr2} $TmpVal "$0" "Comments" "${BrandFullNameInternal}" 0 + ${WriteRegStr2} $TmpVal "$0" "DisplayIcon" "$8,0" 0 + ${WriteRegStr2} $TmpVal "$0" "DisplayName" "${BrandFullNameInternal} (${AppVersion})" 0 + ${WriteRegStr2} $TmpVal "$0" "DisplayVersion" "${AppVersion} (${AB_CD})" 0 + ${WriteRegStr2} $TmpVal "$0" "InstallLocation" "$INSTDIR" 0 + ${WriteRegStr2} $TmpVal "$0" "Publisher" "Mozilla" 0 + ${WriteRegStr2} $TmpVal "$0" "UninstallString" "$7" 0 + ${WriteRegStr2} $TmpVal "$0" "URLInfoAbout" "${URLInfoAbout}" 0 + ${WriteRegStr2} $TmpVal "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0 + ${WriteRegDWORD2} $TmpVal "$0" "NoModify" 1 0 + ${WriteRegDWORD2} $TmpVal "$0" "NoRepair" 1 0 +!macroend +!define SetUninstallKeys "!insertmacro SetUninstallKeys" + +; File handler keys and name value pairs that may need to be created during +; install or upgrade. +!macro FixFileKeys + ReadRegStr $0 HKLM "Software\Classes\.shtml" "Content Type" + ${If} $0 == "" + StrCpy $0 "Software\Classes\.shtml" + ${WriteRegStr2} $TmpVal "$0" "" "shtmlfile" 0 + ${WriteRegStr2} $TmpVal "$0" "Content Type" "text/html" 0 + ${WriteRegStr2} $TmpVal "$0" "PerceivedType" "text" 0 + ${EndIf} + + ReadRegStr $0 HKLM "Software\Classes\.xht" "Content Type" + ${If} $0 == "" + StrCpy $0 "Software\Classes\.xht" + ${WriteRegStr2} $TmpVal "$0" "" "xhtfile" 0 + ${WriteRegStr2} $TmpVal "$0" "Content Type" "application/xhtml+xml" 0 + ${EndIf} + + ReadRegStr $0 HKLM "Software\Classes\.xhtml" "Content Type" + ${If} $0 == "" + StrCpy $0 "Software\Classes\.xhtml" + ${WriteRegStr2} $TmpVal "$0" "" "xhtmlfile" 0 + ${WriteRegStr2} $TmpVal "$0" "Content Type" "application/xhtml+xml" 0 + ${EndIf} +!macroend +!define FixFileKeys "!insertmacro FixFileKeys" + +; Protocol handler keys and name value pairs that may need to be updated during +; install or upgrade. +!macro FixProtocolKeys + ; Bug 301073 Comment #9 makes it so Firefox no longer supports launching + ; chrome urls from the shell so remove it during install or update if the + ; DefaultIcon is from firefox.exe. + ReadRegStr $0 HKLM "Software\Classes\chrome\DefaultIcon" "" + ${Unless} $0 == "" + StrCpy $0 "$0" "" -13 + StrCpy $0 "$0" 11 + ${If} "$0" == "firefox.exe" + DeleteRegKey HKLM "Software\Classes\chrome" + ${EndIf} + ${EndUnless} + + ; Store the command to open the app with an url in a register for easy access. + GetFullPathName $8 "$INSTDIR\${FileMainEXE}" + StrCpy $1 "$\"$8$\" -url $\"%1$\" -requestPending" + + ; Only set the gopher key if it doesn't already exist with a default value + ReadRegStr $0 HKLM "Software\Classes\gopher" "" + ${If} $0 == "" + ${AddHandlerValues} "Software\Classes\gopher" "$1" "$8,0" "URL:Gopher Protocol" "true" "true" + ${EndIf} + + ; Always set the file and protocol handlers since they may specify a + ; different path and the path is used by Vista when setting associations. + ${AddHandlerValues} "Software\Classes\FirefoxURL" "$1" "$8,0" "${AppRegName} URL" "true" "true" + + ; An empty string is used for the 5th param because FirefoxHTML is not a + ; protocol handler + ${AddHandlerValues} "Software\Classes\FirefoxHTML" "$1" "$8,1" "${AppRegName} Document" "" "true" +!macroend +!define FixProtocolKeys "!insertmacro FixProtocolKeys" diff --git a/mozilla/browser/installer/windows/nsis/uninstaller.nsi b/mozilla/browser/installer/windows/nsis/uninstaller.nsi index 1f8e4172db1..81fb4aed047 100755 --- a/mozilla/browser/installer/windows/nsis/uninstaller.nsi +++ b/mozilla/browser/installer/windows/nsis/uninstaller.nsi @@ -48,6 +48,9 @@ CRCCheck on !addplugindir ./ +; prevents compiling of the reg write logging. +!define NO_LOG + Var TmpVal ; Other included files may depend upon these includes! @@ -59,7 +62,11 @@ Var TmpVal !include WordFunc.nsh !include MUI.nsh +!insertmacro GetOptions !insertmacro GetParameters +!insertmacro StrFilter +!insertmacro WordReplace + !insertmacro un.LineFind !insertmacro un.TrimNewLines @@ -70,14 +77,24 @@ Var TmpVal !include locales.nsi !include version.nsh +; This is named BrandShortName helper because we use this for software update +; post update cleanup. +VIAddVersionKey "FileDescription" "${BrandShortName} Helper" + +!insertmacro AddHandlerValues +!insertmacro RegCleanMain +!insertmacro RegCleanUninstall +!insertmacro WriteRegStr2 +!insertmacro WriteRegDWORD2 !insertmacro un.RegCleanMain !insertmacro un.RegCleanUninstall !insertmacro un.CloseApp !insertmacro un.GetSecondInstallPath -!insertmacro un.IsVista + +!include shared.nsh Name "${BrandFullName}" -OutFile "uninst.exe" +OutFile "helper.exe" InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} (${AppVersion})" "InstallLocation" InstallDir "$PROGRAMFILES\${BrandFullName}" ShowUnInstDetails nevershow @@ -173,18 +190,19 @@ Section "Uninstall" ; 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 + ${If} "$INSTDIR" == "$R1" ; XXXrstrong - if there is another installation of the same app ideally we ; would just modify these values. The GetSecondInstallPath macro could be ; made to provide enough information to do this. DeleteRegKey HKLM "Software\Clients\StartMenuInternet\${FileMainEXE}" + DeleteRegValue HKLM "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\$R9" + StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\${FileMainEXE}" DeleteRegKey HKLM "$0" DeleteRegKey HKCU "$0" StrCpy $0 "MIME\Database\Content Type\application/x-xpinstall;app=firefox" @@ -197,7 +215,7 @@ Section "Uninstall" Push $R0 ${GetParentDir} Pop $R1 - ${If} $INSTDIR == $R1 + ${If} "$INSTDIR" == "$R1" WriteRegStr HKLM "$0" "" "$R9" Push $R9 ${GetParentDir} @@ -206,11 +224,6 @@ Section "Uninstall" ${EndIf} ${EndIf} - ${un.IsVista} $R9 - ${If} $R9 == "true" - DeleteRegValue HKLM "Software\RegisteredApplications" "${DDEApplication}" - ${EndIf} - ; Remove files. If we don't have a log file skip ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log" ; Copy the uninstall log file to a temporary file @@ -380,7 +393,6 @@ Function un.preInstFiles ClearErrors ${un.CloseApp} "true" $(WARN_APP_RUNNING_UNINSTALL) ClearErrors - ; Try one more time and if that fails uninstall what ever we are able to. ${DeleteFile} "$INSTDIR\${FileMainEXE}" ${EndIf} ${EndIf} @@ -426,61 +438,57 @@ Function .onInit ${EndUnless} ${GetParameters} $R0 - StrCpy $R1 "Software\Clients\StartMenuInternet\${FileMainEXE}\InstallInfo" - SetShellVarContext all ; Set $DESKTOP to All Users - - ; Hide icons - initiated from Set Program Access and Defaults - ${If} $R0 == "/HideShortcuts" - WriteRegDWORD HKLM $R1 "IconsVisible" 0 - ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" - SetShellVarContext current ; Set $DESKTOP to the current user's desktop - ${EndUnless} - - ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" - ShellLink::GetShortCutArgs "$DESKTOP\${BrandFullName}.lnk" - Pop $0 - ${If} $0 == "" - ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk" - Pop $0 - ${If} $0 == "$INSTDIR\${FileMainEXE}" - Delete "$DESKTOP\${BrandFullName}.lnk" - ${EndIf} - ${EndIf} - ${EndIf} - - ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" - ShellLink::GetShortCutArgs "$QUICKLAUNCH\${BrandFullName}.lnk" - Pop $0 - ${If} $0 == "" - ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandFullName}.lnk" - Pop $0 - ${If} $0 == "$INSTDIR\${FileMainEXE}" - Delete "$QUICKLAUNCH\${BrandFullName}.lnk" - ${EndIf} - ${EndIf} - ${EndIf} - Abort - ${EndIf} - - ; Show icons - initiated from Set Program Access and Defaults - ${If} $R0 == "/ShowShortcuts" - WriteRegDWORD HKLM $R1 "IconsVisible" 1 - ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" - CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" "" "$INSTDIR\${FileMainEXE}" 0 - ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR" - ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" - SetShellVarContext current ; Set $DESKTOP to the current user's desktop - ${Unless} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" - CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" "" "$INSTDIR\${FileMainEXE}" 0 - ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR" + ${Switch} $R0 + ${Case} "/HideShortcuts" + ${HideShortcuts} + StrCpy $R1 "true" + ${Break} + ${Case} "/ShowShortcuts" + ${ShowShortcuts} + StrCpy $R1 "true" + ${Break} + ${Case} "/SetAsDefaultAppUser" + ${SetAsDefaultAppUser} + StrCpy $R1 "true" + ${Break} + ${Case} "/SetAsDefaultAppGlobal" + ${SetAsDefaultAppGlobal} + StrCpy $R1 "true" + ${Break} + ${Default} + ClearErrors + ${Unless} "$R0" == "" + ${WordReplace} "$R0" "$\"" "" "+" $R0 + ClearErrors + ${GetOptions} "$R0" "/PostUpdate" $R2 + ${Unless} ${Errors} + ${PostUpdate} + ClearErrors + ${GetOptions} "$R0" "/UninstallLog=" $R2 + ${Unless} ${Errors} + ${Unless} "$R2" == "" + GetFullPathName $R3 "$R2" + ${If} ${FileExists} "$R3" + Delete "$INSTDIR\uninstall\*wizard*" + Delete "$INSTDIR\uninstall\uninstall.log" + CopyFiles /SILENT "$R3" "$INSTDIR\uninstall\" + Push $R3 + ${GetParentDir} + Pop $R4 + Delete "$R3" + RmDir "$R4" + ${EndIf} + ${EndUnless} + ${EndUnless} + StrCpy $R1 "true" ${EndUnless} ${EndUnless} - ${EndUnless} - ${Unless} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" - CreateShortCut "$QUICKLAUNCH\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" "" "$INSTDIR\${FileMainEXE}" 0 - ShellLink::SetShortCutWorkingDirectory "$QUICKLAUNCH\${BrandFullName}.lnk" "$INSTDIR" - ${EndUnless} - Abort + ${Break} + ${EndSwitch} + + ${If} $R1 == "true" + System::Call "shell32::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)" + Quit ${EndIf} ; If we made it this far then this installer is being used as an uninstaller. diff --git a/mozilla/browser/installer/windows/packages-static b/mozilla/browser/installer/windows/packages-static index 7eaccaefb4f..b758c634579 100644 --- a/mozilla/browser/installer/windows/packages-static +++ b/mozilla/browser/installer/windows/packages-static @@ -24,7 +24,7 @@ bin\defaults\profile\prefs.js bin\defaults\profile\search.rdf bin\defaults\profile\mimeTypes.rdf bin\defaults\profile\chrome\* -bin\uninstall\uninst.exe +bin\uninstall\helper.exe bin\updater.ini bin\dictionaries\* diff --git a/mozilla/browser/locales/Makefile.in b/mozilla/browser/locales/Makefile.in index c4da4b70426..b8914a16d12 100644 --- a/mozilla/browser/locales/Makefile.in +++ b/mozilla/browser/locales/Makefile.in @@ -193,7 +193,7 @@ endif $(MAKE) -C ../installer/windows CONFIG_DIR=l10ngen l10ngen/setup.exe l10ngen/7zSD.sfx cp ../installer/windows/l10ngen/setup.exe l10n-stage $(NSINSTALL) -D l10n-stage/localized/uninstall - cp ../installer/windows/l10ngen/uninst.exe l10n-stage/localized/uninstall + cp ../installer/windows/l10ngen/helper.exe l10n-stage/localized/uninstall rm -f app.7z cd l10n-stage && \ $(CYGWIN_WRAPPER) 7z a -r -t7z ../app.7z -mx -m0=BCJ2 -m1=LZMA:d24 -m2=LZMA:d19 -m3=LZMA:d19 -mb0:1 -mb0s1:2 -mb0s2:3 @@ -232,7 +232,7 @@ repackage-zip: $(ZIP_IN) ifeq (WINNT,$(OS_ARCH)) $(RM) -r $(STAGEDIST)/uninstall $(NSINSTALL) -D $(STAGEDIST)/uninstall - cp ../installer/windows/l10ngen/uninst.exe $(STAGEDIST)/uninstall + cp ../installer/windows/l10ngen/helper.exe $(STAGEDIST)/uninstall endif $(RM) -r $(DIST)/xpi-stage/locale-$(AB_CD)/chrome/$(AB_CD) cd $(DIST)/xpi-stage/locale-$(AB_CD) && \ diff --git a/mozilla/browser/locales/en-US/installer/custom.properties b/mozilla/browser/locales/en-US/installer/custom.properties index 13a1544ce53..56e8cd1fcb6 100755 --- a/mozilla/browser/locales/en-US/installer/custom.properties +++ b/mozilla/browser/locales/en-US/installer/custom.properties @@ -55,7 +55,8 @@ DOMI_TITLE=DOM Inspector DOMI_TEXT=Inspects the structure and properties of a window and its contents. QFA_TITLE=Quality Feedback Agent QFA_TEXT=Sends information about program crashes to Mozilla. -OPTIONS=$(^NameDA) &Options +CONTEXT_OPTIONS=${BrandShortName} &Options +CONTEXT_SAFE_MODE=${BrandShortName} &Safe Mode SAFE_MODE=Safe Mode OPTIONS_PAGE_TITLE=Setup Type OPTIONS_PAGE_SUBTITLE=Choose setup options diff --git a/mozilla/calendar/installer/windows/nsis/installer.nsi b/mozilla/calendar/installer/windows/nsis/installer.nsi index 44a2ee6865c..77ab5dde9c8 100644 --- a/mozilla/calendar/installer/windows/nsis/installer.nsi +++ b/mozilla/calendar/installer/windows/nsis/installer.nsi @@ -91,6 +91,8 @@ Var fhUninstallLog !include locales.nsi !include version.nsh +VIAddVersionKey "FileDescription" "${BrandShortName} Installer" + !insertmacro RegCleanMain !insertmacro RegCleanUninstall !insertmacro CloseApp diff --git a/mozilla/calendar/installer/windows/nsis/uninstaller.nsi b/mozilla/calendar/installer/windows/nsis/uninstaller.nsi index 0f8cddb634e..67847d5b278 100755 --- a/mozilla/calendar/installer/windows/nsis/uninstaller.nsi +++ b/mozilla/calendar/installer/windows/nsis/uninstaller.nsi @@ -70,6 +70,10 @@ Var TmpVal !include locales.nsi !include version.nsh +; This is named BrandShortName helper because we use this for software update +; post update cleanup. +VIAddVersionKey "FileDescription" "${BrandShortName} Helper" + !insertmacro un.RegCleanMain !insertmacro un.RegCleanUninstall !insertmacro un.CloseApp diff --git a/mozilla/mail/installer/windows/nsis/installer.nsi b/mozilla/mail/installer/windows/nsis/installer.nsi index 9fd443ae776..bdb51b71efc 100755 --- a/mozilla/mail/installer/windows/nsis/installer.nsi +++ b/mozilla/mail/installer/windows/nsis/installer.nsi @@ -92,6 +92,8 @@ Var ShortPathNameToExe !include locales.nsi !include version.nsh +VIAddVersionKey "FileDescription" "${BrandShortName} Installer" + !insertmacro RegCleanMain !insertmacro RegCleanUninstall !insertmacro CloseApp diff --git a/mozilla/mail/installer/windows/nsis/uninstaller.nsi b/mozilla/mail/installer/windows/nsis/uninstaller.nsi index 1a388e2ab80..60f30f38d8e 100755 --- a/mozilla/mail/installer/windows/nsis/uninstaller.nsi +++ b/mozilla/mail/installer/windows/nsis/uninstaller.nsi @@ -71,6 +71,10 @@ Var TmpVal !include locales.nsi !include version.nsh +; This is named BrandShortName helper because we use this for software update +; post update cleanup. +VIAddVersionKey "FileDescription" "${BrandShortName} Helper" + !insertmacro un.RegCleanMain !insertmacro un.RegCleanUninstall !insertmacro un.CloseApp diff --git a/mozilla/toolkit/mozapps/installer/windows/nsis/common.nsh b/mozilla/toolkit/mozapps/installer/windows/nsis/common.nsh index dbe654aeed7..15a2e557f64 100755 --- a/mozilla/toolkit/mozapps/installer/windows/nsis/common.nsh +++ b/mozilla/toolkit/mozapps/installer/windows/nsis/common.nsh @@ -530,87 +530,6 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !verbose pop !macroend -/** - * Checks whether the system is running Vista. If the system is running Vista - * this will return true... if not, this will return false. - * - * IMPORTANT! $R9 will be overwritten by this macro with the return value so - * protect yourself! - * - * @return _RESULT - * true if the system is running Vista otherwise false. - * - * $R7 = value of CurrentVersion from call to ReadRegStr - * $R8 = leftmost char from $R7 used for comparison. If this is 6 then the - * system is running Vista. - * $R9 = _RESULT - */ -!macro IsVista - - !ifndef ${_MOZFUNC_UN}IsVista - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !define ${_MOZFUNC_UN}IsVista "!insertmacro ${_MOZFUNC_UN}IsVistaCall" - - Function ${_MOZFUNC_UN}IsVista - Push $R7 - Push $R8 - - StrCpy $R9 "false" - - ClearErrors - - ReadRegStr $R7 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion - IfErrors end 0 - - StrCpy $R8 $R7 1 - StrCmp $R8 "6" 0 end - StrCpy $R9 "true" - - end: - - ClearErrors - - Pop $R8 - Pop $R7 - Push $R9 - FunctionEnd - - !verbose pop - !endif -!macroend - -!macro IsVistaCall _RESULT - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Call IsVista - Pop ${_RESULT} - !verbose pop -!macroend - -!macro un.IsVistaCall _RESULT - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Call un.IsVista - Pop ${_RESULT} - !verbose pop -!macroend - -!macro un.IsVista - !ifndef un.IsVista - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !undef _MOZFUNC_UN - !define _MOZFUNC_UN "un." - - !insertmacro IsVista - - !undef _MOZFUNC_UN - !define _MOZFUNC_UN - !verbose pop - !endif -!macroend - /** * Checks whether we can write to the install directory. If the install * directory already exists this will attempt to create a temporary file in the @@ -1190,12 +1109,15 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack ClearErrors WriteRegStr SHCTX "$R6" "$R7" "$R8" + +!ifndef NO_LOG IfErrors 0 +3 FileWrite $fhInstallLog " ** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **$\r$\n" GoTo +4 IntCmp $R9 1 0 +2 FileWrite $fhUninstallLog "RegVal: $R5 | $R6 | $R7$\r$\n" FileWrite $fhInstallLog " Added Registry String: $R5 | $R6 | $R7 | $R8$\r$\n" +!endif Exch $R5 Exch 4 @@ -1292,12 +1214,14 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack ClearErrors WriteRegDWORD SHCTX "$R6" "$R7" "$R8" +!ifndef NO_LOG IfErrors 0 +3 FileWrite $fhInstallLog " ** ERROR Adding Registry DWord: $R5 | $R6 | $R7 | $R8 **$\r$\n" GoTo +4 IntCmp $R5 1 0 +2 FileWrite $fhUninstallLog "RegVal: $R5 | $R6 | $R7$\r$\n" FileWrite $fhInstallLog " Added Registry DWord: $R5 | $R6 | $R7 | $R8$\r$\n" +!endif Exch $R5 Exch 4 @@ -1394,12 +1318,15 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack ClearErrors WriteRegStr HKCR "$R6" "$R7" "$R8" + +!ifndef NO_LOG IfErrors 0 +3 FileWrite $fhInstallLog " ** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **$\r$\n" GoTo +4 IntCmp $R5 1 0 +2 FileWrite $fhUninstallLog "RegVal: $R5 | $R6 | $R7$\r$\n" FileWrite $fhInstallLog " Added Registry String: $R5 | $R6 | $R7 | $R8$\r$\n" +!endif Exch $R5 Exch 4 @@ -1515,6 +1442,7 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack ; see definition of RegCreateKey System::Call "${RegCreateKey}($R6, '$R8', .r14) .r15" +!ifndef NO_LOG ; if $R5 is not 0 then there was an error creating the registry key. IntCmp $R5 0 +3 FileWrite $fhInstallLog " ** ERROR Adding Registry Key: $R7 | $R8 **$\r$\n" @@ -1522,6 +1450,7 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack IntCmp $R9 1 0 +2 FileWrite $fhUninstallLog "RegKey: $R7 | $R8$\r$\n" FileWrite $fhInstallLog " Added Registry Key: $R7 | $R8$\r$\n" +!endif Pop $R4 Pop $R5 @@ -1572,114 +1501,6 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !endif !macroend -/** - * Finds an installation of the application so we can force an install into an - * existing location for Vista. This uses SHCTX to determine the - * registry hive so you must call SetShellVarContext first. - * - * IMPORTANT! $R9 will be overwritten by this macro with the return value so - * protect yourself! - * - * @param _KEY - * The registry subkey (typically this will be Software\Mozilla). - * @return _RESULT - * false if an install isn't found, path to the main exe if an install - * is found. - * - * $R3 = _KEY - * $R4 = value returned from the outer loop's EnumRegKey - * $R5 = value returned from ReadRegStr - * $R6 = counter for the outer loop's EnumRegKey - * $R7 = value returned popped from the stack for GetPathFromRegStr macro - * $R8 = value returned popped from the stack for GetParentDir macro - * $R9 = _RESULT - */ -!macro GetExistingInstallPath - - !ifndef ${_MOZFUNC_UN}GetExistingInstallPath - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !define ${_MOZFUNC_UN}GetExistingInstallPath "!insertmacro ${_MOZFUNC_UN}GetExistingInstallPathCall" - - Function ${_MOZFUNC_UN}GetExistingInstallPath - Exch $R3 - Push $R4 - Push $R5 - Push $R6 - Push $R7 - Push $R8 - - StrCpy $R9 "false" - StrCpy $R6 0 ; set the counter for the loop to 0 - - loop: - EnumRegKey $R4 SHCTX $R3 $R6 - StrCmp $R4 "" end ; if empty there are no more keys to enumerate - IntOp $R6 $R6 + 1 ; increment the loop's counter - ClearErrors - ReadRegStr $R5 SHCTX "$R3\$R4\bin" "PathToExe" - IfErrors loop - Push $R5 - ${GetPathFromRegStr} - Pop $R7 - - IfFileExists "$R7" 0 +5 - Push "$R7" - ${GetParent} "$R7" $R8 - StrCpy $R9 "$R8" - GoTo end - - GoTo loop - - end: - ClearErrors - - Pop $R8 - Pop $R7 - Pop $R6 - Pop $R5 - Pop $R4 - Exch $R3 - Push $R9 - FunctionEnd - - !verbose pop - !endif -!macroend - -!macro GetExistingInstallPathCall _KEY _RESULT - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Push "${_KEY}" - Call GetExistingInstallPath - Pop ${_RESULT} - !verbose pop -!macroend - -!macro un.GetExistingInstallPathCall _KEY _RESULT - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Push "${_KEY}" - Call un.GetExistingInstallPath - Pop ${_RESULT} - !verbose pop -!macroend - -!macro un.GetExistingInstallPath - !ifndef un.GetExistingInstallPath - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !undef _MOZFUNC_UN - !define _MOZFUNC_UN "un." - - !insertmacro GetExistingInstallPath - - !undef _MOZFUNC_UN - !define _MOZFUNC_UN - !verbose pop - !endif -!macroend - /** * Finds a second installation of the application so we can make informed * decisions about registry operations. This uses SHCTX to determine the @@ -1791,6 +1612,137 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !endif !macroend +/** + * Writes common registry values for a handler using SHCTX. + * @param _KEY + * The subkey in relation to the key root. + * @param _VALOPEN + * The path and args to launch the application. + * @param _VALICON + * The path to an exe that contains an icon and the icon resource id. + * @param _DISPNAME + * The display name for the handler. If emtpy no value will be set. + * @param _ISPROTOCOL + * Sets protocol handler specific registry values when "true". + * @param _ISDDE + * Sets DDE specific registry values when "true". + * + * $R3 = string value of the current registry key path. + * $R4 = _KEY + * $R5 = _VALOPEN + * $R6 = _VALICON + * $R7 = _DISPNAME + * $R8 = _ISPROTOCOL + * $R9 = _ISDDE + */ +!macro AddHandlerValues + + !ifndef ${_MOZFUNC_UN}AddHandlerValues + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}AddHandlerValues "!insertmacro ${_MOZFUNC_UN}AddHandlerValuesCall" + + Function ${_MOZFUNC_UN}AddHandlerValues + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Exch 4 + Exch $R5 + Exch 5 + Exch $R4 + Push $R3 + + StrCmp "$R7" "" +6 0 + ReadRegStr $R3 SHCTX "$R4" "FriendlyTypeName" + + StrCmp "$R3" "" 0 +3 + WriteRegStr SHCTX "$R4" "" "$R7" + WriteRegStr SHCTX "$R4" "FriendlyTypeName" "$R7" + + StrCmp "$R8" "true" 0 +4 + DeleteRegValue SHCTX "$R4" "EditFlags" + WriteRegBin SHCTX "$R4" "EditFlags" 2 + WriteRegStr SHCTX "$R4" "URL Protocol" "" + + StrCmp "$R9" "true" 0 +13 + WriteRegStr SHCTX "$R4\DefaultIcon" "" "$R6" + WriteRegStr SHCTX "$R4\shell\open\command" "" "$R5" + WriteRegStr SHCTX "$R4\shell\open\ddeexec" "" "$\"%1$\",,0,0,,,," + WriteRegStr SHCTX "$R4\shell\open\ddeexec" "NoActivateHandler" "" + WriteRegStr SHCTX "$R4\shell\open\ddeexec\Application" "" "${DDEApplication}" + WriteRegStr SHCTX "$R4\shell\open\ddeexec\Topic" "" "WWW_OpenURL" + ; The ifexec key may have been added by another application so try to + ; delete it to prevent it from breaking this app's shell integration. + ; Also, IE 6 and below doesn't remove this key when it sets itself as the + ; default handler and if this key exists IE's shell integration breaks. + DeleteRegKey HKLM "$R4\shell\open\ddeexec\ifexec" + DeleteRegKey HKCU "$R4\shell\open\ddeexec\ifexec" + + ClearErrors + + Pop $R3 + Exch $R4 + Exch 5 + Exch $R5 + Exch 4 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Push "${_VALOPEN}" + Push "${_VALICON}" + Push "${_DISPNAME}" + Push "${_ISPROTOCOL}" + Push "${_ISDDE}" + Call AddHandlerValues + !verbose pop +!macroend + +!macro un.AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Push "${_VALOPEN}" + Push "${_VALICON}" + Push "${_DISPNAME}" + Push "${_ISPROTOCOL}" + Push "${_ISDDE}" + Call un.AddHandlerValues + !verbose pop +!macroend + +!macro un.AddHandlerValues + !ifndef un.AddHandlerValues + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro AddHandlerValues + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + /** * Displays a error message when a file can't be copied. * diff --git a/mozilla/toolkit/mozapps/installer/windows/nsis/makensis.mk b/mozilla/toolkit/mozapps/installer/windows/nsis/makensis.mk index 4870e9585a9..d478815e667 100755 --- a/mozilla/toolkit/mozapps/installer/windows/nsis/makensis.mk +++ b/mozilla/toolkit/mozapps/installer/windows/nsis/makensis.mk @@ -80,4 +80,8 @@ uninstaller:: $(INSTALL) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/setup.ico $(CONFIG_DIR) cd $(CONFIG_DIR) && makensis.exe uninstaller.nsi $(NSINSTALL) -D $(DIST)/bin/uninstall +ifdef MOZ_PHOENIX + cp $(CONFIG_DIR)/helper.exe $(DIST)/bin/uninstall +else cp $(CONFIG_DIR)/uninst.exe $(DIST)/bin/uninstall +endif diff --git a/mozilla/toolkit/mozapps/installer/windows/nsis/version.nsh b/mozilla/toolkit/mozapps/installer/windows/nsis/version.nsh index 7fa568f404b..454ba826f00 100755 --- a/mozilla/toolkit/mozapps/installer/windows/nsis/version.nsh +++ b/mozilla/toolkit/mozapps/installer/windows/nsis/version.nsh @@ -12,6 +12,5 @@ VIAddVersionKey "ProductName" "${BrandShortName}" VIAddVersionKey "CompanyName" "${CompanyName}" VIAddVersionKey "LegalTrademarks" "${BrandShortName} is a Trademark of The Mozilla Foundation." VIAddVersionKey "LegalCopyright" "${CompanyName}" -VIAddVersionKey "FileDescription" "${BrandShortName} Installer" VIAddVersionKey "FileVersion" "${AppVersion}" ;VIAddVersionKey "Comments" "Comments" diff --git a/mozilla/toolkit/mozapps/update/content/updates.js b/mozilla/toolkit/mozapps/update/content/updates.js index d7ab75c38cd..a6c507855d6 100755 --- a/mozilla/toolkit/mozapps/update/content/updates.js +++ b/mozilla/toolkit/mozapps/update/content/updates.js @@ -73,7 +73,7 @@ var gLogEnabled = { }; * The string to write to the error console.. */ function LOG(module, string) { - if (module in gLogEnabled) { + if (module in gLogEnabled || "all" in gLogEnabled) { dump("*** " + module + ":" + string + "\n"); gConsole.logStringMessage(string); } diff --git a/mozilla/toolkit/mozapps/update/src/nsPostUpdateWin.js b/mozilla/toolkit/mozapps/update/src/nsPostUpdateWin.js index 6b2f16e3058..d9a1bb5ccab 100644 --- a/mozilla/toolkit/mozapps/update/src/nsPostUpdateWin.js +++ b/mozilla/toolkit/mozapps/update/src/nsPostUpdateWin.js @@ -43,12 +43,12 @@ */ const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties"; -const URI_UNINSTALL_PROPERTIES = "chrome://branding/content/uninstall.properties"; const KEY_APPDIR = "XCurProcD"; -const KEY_COMPONENTS_DIR = "ComsD"; -const KEY_PLUGINS_DIR = "APlugns"; -const KEY_EXECUTABLE_FILE = "XREExeF"; +const KEY_TMPDIR = "TmpD"; +const KEY_LOCALDATA = "DefProfLRt"; +const KEY_PROGRAMFILES = "ProgF"; +const KEY_UAPPDATA = "UAppData"; // see prio.h const PR_RDONLY = 0x01; @@ -56,16 +56,23 @@ const PR_WRONLY = 0x02; const PR_APPEND = 0x10; const PERMS_FILE = 0644; +const PERMS_DIR = 0700; const nsIWindowsRegKey = Components.interfaces.nsIWindowsRegKey; +var gConsole = null; +var gAppUpdateLogPostUpdate = false; + //----------------------------------------------------------------------------- /** * Console logging support */ function LOG(s) { - dump("*** PostUpdateWin: " + s + "\n"); + if (gAppUpdateLogPostUpdate) { + dump("*** PostUpdateWin: " + s + "\n"); + gConsole.logStringMessage(s); + } } /** @@ -122,24 +129,6 @@ function openFileOutputStream(file, flags) { return stream; } -/** - * Gets the current value of the locale. It's possible for this preference to - * be localized, so we have to do a little extra work here. Similar code - * exists in nsHttpHandler.cpp when building the UA string. - */ -function getLocale() { - const prefName = "general.useragent.locale"; - var prefs = - Components.classes["@mozilla.org/preferences-service;1"]. - getService(Components.interfaces.nsIPrefBranch); - try { - return prefs.getComplexValue(prefName, - Components.interfaces.nsIPrefLocalizedString).data; - } catch (e) {} - - return prefs.getCharPref(prefName); -} - //----------------------------------------------------------------------------- const PREFIX_FILE = "File: "; @@ -179,20 +168,49 @@ InstallLogWriter.prototype = { * updates/0 directory has already been cleaned out (see bug 311302). */ _getUpdateLogFile: function() { - var file = getFile(KEY_APPDIR); - file.append("updates"); - file.append("0"); - file.append("update.log"); - if (file.exists()) - return file; + function appendUpdateLogPath(root) { + var file = root.clone(); + file.append("updates"); + file.append("0"); + file.append("update.log"); + if (file.exists()) + return file; - file = getFile(KEY_APPDIR); - file.append("updates"); - file.append("last-update.log"); - if (file.exists()) - return file; + file = root; + file.append("updates"); + file.append("last-update.log"); + if (file.exists()) + return file; - return null; + return null; + } + + // See the local appdata first if app dir is under Program Files. + var file = null; + var updRoot = getFile(KEY_APPDIR); + var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties); + var programFilesDir = fileLocator.get(KEY_PROGRAMFILES, + Components.interfaces.nsILocalFile); + if (programFilesDir.contains(updRoot, true)) { + var relativePath = updRoot.QueryInterface(Components.interfaces.nsILocalFile). + getRelativeDescriptor(programFilesDir); + var userLocalDir = fileLocator.get(KEY_LOCALDATA, + Components.interfaces.nsILocalFile).parent; + updRoot.setRelativeDescriptor(userLocalDir, relativePath); + file = appendUpdateLogPath(updRoot); + + // When updating from Fx 2.0.0.1 to 2.0.0.3 (or later) on Vista, + // we will have to see also user app data (see bug 351949). + if (!file) + file = appendUpdateLogPath(getFile(KEY_UAPPDATA)); + } + + // See the app dir if not found or app dir is out of Program Files. + if (!file) + file = appendUpdateLogPath(getFile(KEY_APPDIR)); + + return file; }, /** @@ -337,8 +355,27 @@ InstallLogWriter.prototype = { if (newEntries.length == 0) return; + // since we are not running with elevated privs, we can't write out + // the log file (at least, not on Vista). So, write the output to + // temp, and then later, we'll pass the file (gCopiedLog) to + // the post update clean up process, which can copy it to + // the desired location (because it will have elevated privs) + gCopiedLog = getFile(KEY_TMPDIR); + gCopiedLog.append("uninstall"); + gCopiedLog.createUnique(gCopiedLog.DIRECTORY_TYPE, PERMS_DIR); + if (uninstallLog) + uninstallLog.copyTo(gCopiedLog, "uninstall.log"); + gCopiedLog.append("uninstall.log"); + + LOG("uninstallLog = " + uninstallLog.path); + LOG("copiedLog = " + gCopiedLog.path); + + if (!gCopiedLog.exists()) + gCopiedLog.create(Components.interfaces.nsILocalFile.NORMAL_FILE_TYPE, + PERMS_FILE); + this._outputStream = - openFileOutputStream(uninstallLog, PR_WRONLY | PR_APPEND); + openFileOutputStream(gCopiedLog, PR_WRONLY | PR_APPEND); // The NSIS uninstaller deletes all directories where the installer has // added a file if the directory is empty after the files have been removed @@ -356,12 +393,15 @@ InstallLogWriter.prototype = { }; var installLogWriter; +var gCopiedLog; //----------------------------------------------------------------------------- /** - * A thin wrapper around nsIWindowsRegKey that keeps track of its path - * and notifies the installLogWriter when modifications are made. + * A thin wrapper around nsIWindowsRegKey + * note, only the "read" methods are exposed. If you want to write + * to the registry on Vista, you need to be a priveleged app. + * We've moved that code into the uninstaller. */ function RegKey() { // Internally, we may pass parameters to this constructor. @@ -381,12 +421,11 @@ RegKey.prototype = { _path: null, ACCESS_READ: nsIWindowsRegKey.ACCESS_READ, - ACCESS_WRITE: nsIWindowsRegKey.ACCESS_WRITE, - ACCESS_ALL: nsIWindowsRegKey.ACCESS_ALL, ROOT_KEY_CURRENT_USER: nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, ROOT_KEY_LOCAL_MACHINE: nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, - + ROOT_KEY_CLASSES_ROOT: nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT, + close: function() { this._key.close(); this._root = null; @@ -404,24 +443,10 @@ RegKey.prototype = { return new RegKey(child, this._root, this._path + "\\" + path); }, - createChild: function(path, mode) { - var child = this._key.createChild(path, mode); - var key = new RegKey(child, this._root, this._path + "\\" + path); - return key; - }, - readStringValue: function(name) { return this._key.readStringValue(name); }, - writeStringValue: function(name, value) { - this._key.writeStringValue(name, value); - }, - - writeIntValue: function(name, value) { - this._key.writeIntValue(name, value); - }, - hasValue: function(name) { return this._key.hasValue(name); }, @@ -438,13 +463,12 @@ RegKey.prototype = { return this._key.getChildName(index); }, - removeChild: function(name) { - this._key.removeChild(name); - }, - toString: function() { var root; switch (this._root) { + case this.ROOT_KEY_CLASSES_ROOT: + root = "HKEY_KEY_CLASSES_ROOT"; + break; case this.ROOT_KEY_LOCAL_MACHINE: root = "HKEY_LOCAL_MACHINE"; break; @@ -459,86 +483,14 @@ RegKey.prototype = { } }; -//----------------------------------------------------------------------------- - -/* -RegKey.prototype = { - // The name of the registry key - name: ""; - - // An array of strings, where each even-indexed string names a value, - // and the subsequent string provides data for the value. - values: []; - - // An array of RegKey objects. - children: []; -} -*/ - -/** - * This function creates a heirarchy of registry keys. If any of the - * keys or values already exist, then they will be updated instead. - * @param rootKey - * The root registry key from which to create the new registry - * keys. - * @param data - * A JS object with properties: "name", "values", and "children" - * as defined above. All children of this key will be created. - */ -function createRegistryKeys(rootKey, data) { - var key; - try { - key = rootKey.createChild(data.name, rootKey.ACCESS_WRITE); - var i; - if ("values" in data) { - for (i = 0; i < data.values.length; i += 2) - key.writeStringValue(data.values[i], data.values[i + 1]); - } - if ("children" in data) { - for (i = 0; i < data.children.length; ++i) - createRegistryKeys(key, data.children[i]); - } - key.close(); - } catch (e) { - LOG(e); - if (key) - key.close(); - } -} - -/** - * This function deletes the specified registry key and optionally all of its - * children. - * @param rootKey - * The parent nsIwindowRegKey of the key to delete. - * @param name - * The name of the key to delete. - * @param recurse - * Pass true to also delete all children of the named key. Take care! - */ -function deleteRegistryKey(rootKey, name, recurse) { - if (!rootKey.hasChild(name)) { - LOG("deleteRegistryKey: rootKey does not have child: \"" + name + "\""); - return; - } - if (recurse) { - var key = rootKey.openChild(name, rootKey.ACCESS_ALL); - try { - for (var i = key.childCount - 1; i >= 0; --i) - deleteRegistryKey(key, key.getChildName(i), true); - } finally { - key.close(); - } - } - rootKey.removeChild(name); -} - /** * This method walks the registry looking for the registry keys of * the previous version of the application. */ -function locateOldInstall(key, ourInstallDir) { - var result, childKey, productKey, mainKey; +function haveOldInstall(key, brandFullName, version) { + var ourInstallDir = getFile(KEY_APPDIR); + var result = false; + var childKey, productKey, mainKey; try { for (var i = 0; i < key.childCount; ++i) { var childName = key.getChildName(i); @@ -550,14 +502,14 @@ function locateOldInstall(key, ourInstallDir) { if (productKey.hasChild("Main")) { mainKey = productKey.openChild("Main", key.ACCESS_READ); var installDir = mainKey.readStringValue("Install Directory"); - var menuPath = mainKey.readStringValue("Program Folder Path"); mainKey.close(); - if (newFile(installDir).equals(ourInstallDir)) { - result = new Object(); - result.fullName = childName; - result.versionWithLocale = productVer; - result.version = productVer.split(" ")[0]; - result.menuPath = menuPath; + LOG("old install? " + installDir + " vs " + ourInstallDir.path); + LOG("old install? " + childName + " vs " + brandFullName); + LOG("old install? " + productVer.split(" ")[0] + " vs " + version); + if (newFile(installDir).equals(ourInstallDir) && + (childName != brandFullName || + productVer.split(" ")[0] != version)) { + result = true; } } productKey.close(); @@ -570,7 +522,7 @@ function locateOldInstall(key, ourInstallDir) { break; } } catch (e) { - result = null; + result = false; if (childKey) childKey.close(); if (productKey) @@ -581,239 +533,62 @@ function locateOldInstall(key, ourInstallDir) { return result; } -/** - * Delete registry keys left-over from the previous version of the app - * installed at our location. - */ -function deleteOldRegKeys(key, info) { - deleteRegistryKey(key, info.fullName + " " + info.version, true); - var productKey = key.openChild(info.fullName, key.ACCESS_ALL); - var productCount; +function checkRegistry() +{ + // XXX todo + // this is firefox specific + // figure out what to do about tbird and sunbird, etc + LOG("checkRegistry"); + + var result = false; try { - deleteRegistryKey(productKey, info.versionWithLocale, true); - productCount = productKey.childCount; - } finally { - productKey.close(); + var key = new RegKey(); + key.open(RegKey.prototype.ROOT_KEY_CLASSES_ROOT, "FirefoxHTML\\shell\\open\\command", key.ACCESS_READ); + var commandKey = key.readStringValue(""); + LOG("commandKey = " + commandKey); + // if "-requestPending" is not found, we need to do the cleanup + result = (commandKey.indexOf("-requestPending") == -1); + } catch (e) { + LOG("failed to open command key for FirefoxHTML: " + e); } - if (productCount == 0) - key.removeChild(info.fullName); + key.close(); + return result; } -/** - * The installer sets various registry keys and values that may need to be - * updated. - * - * This operation is a bit tricky since we do not know the previous value of - * brandFullName. As a result, we must walk the registry looking for an - * existing key that references the same install directory. We assume that - * the value of vendorShortName does not change across updates. - */ -function updateRegistry(rootKey) { - LOG("updateRegistry"); - - var ourInstallDir = getFile(KEY_APPDIR); - - var app = - Components.classes["@mozilla.org/xre/app-info;1"]. - getService(Components.interfaces.nsIXULAppInfo). - QueryInterface(Components.interfaces.nsIXULRuntime); - - var sbs = - Components.classes["@mozilla.org/intl/stringbundle;1"]. - getService(Components.interfaces.nsIStringBundleService); - var brandBundle = sbs.createBundle(URI_BRAND_PROPERTIES); - var brandFullName = brandBundle.GetStringFromName("brandFullName"); - - var vendorShortName; - try { - // The Thunderbird vendorShortName is "Mozilla Thunderbird", but we - // just want "Thunderbird", so allow it to be overridden in prefs. - - var prefs = - Components.classes["@mozilla.org/preferences-service;1"]. - getService(Components.interfaces.nsIPrefBranch); - - vendorShortName = prefs.getCharPref("app.update.vendorName.override"); - } - catch (e) { - vendorShortName = brandBundle.GetStringFromName("vendorShortName"); - } - +function checkOldInstall(rootKey, vendorShortName, brandFullName, version) +{ var key = new RegKey(); + var result = false; - var oldInstall; try { key.open(rootKey, "SOFTWARE\\" + vendorShortName, key.ACCESS_READ); - oldInstall = locateOldInstall(key, ourInstallDir); - } catch (e) {} - key.close(); - - if (!oldInstall) { - LOG("no existing registry keys found"); - return; + LOG("checkOldInstall: " + key + " " + brandFullName + " " + version); + result = haveOldInstall(key, brandFullName, version); + } catch (e) { + LOG("failed trying to find old install: " + e); } - - const uninstallRoot = - "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; - // Maybe nothing needs to be changed... - if (oldInstall.fullName == brandFullName && - oldInstall.version == app.version) { - var uninst = getFile(KEY_APPDIR); - uninst.append("uninstall"); - uninst.append("uninst.exe"); - var uninstString = uninst.path; - nameWithVersion = oldInstall.fullName + " (" + oldInstall.version + ")"; - try { - key.open(rootKey, uninstallRoot + "\\" + nameWithVersion, key.ACCESS_READ); - var regUninstString = key.readStringValue("UninstallString"); - if (regUninstString != uninstString) { - LOG("updating UninstallString registry value"); - key.close(); - key.open(rootKey, uninstallRoot, key.ACCESS_READ); - createRegistryKeys(key, { name: nameWithVersion, - values: ["UninstallString", uninstString] }); - } else { - LOG("registry is up-to-date"); - } - } catch (e) {} - key.close(); - return; - } - - // Delete the old keys: - try { - key.open(rootKey, "SOFTWARE\\" + vendorShortName, key.ACCESS_READ); - deleteOldRegKeys(key, oldInstall); - } catch (e) {} - key.close(); - - // Create the new keys: - - var versionWithLocale = app.version + " (" + getLocale() + ")"; - var installPath = ourInstallDir.path + "\\"; - var pathToExe = getFile(KEY_EXECUTABLE_FILE).path; - - var Key_bin = { - name: "bin", - values: [ - "PathToExe", pathToExe - ] - }; - var Key_extensions = { - name: "Extensions", - values: [ - "Components", getFile(KEY_COMPONENTS_DIR).path + "\\", - "Plugins", getFile(KEY_PLUGINS_DIR).path + "\\" - ] - }; - var Key_nameWithVersion = { - name: brandFullName + " " + app.version, - values: [ - "GeckoVer", app.platformVersion - ], - children: [ - Key_bin, - Key_extensions - ] - }; - var Key_main = { - name: "Main", - values: [ - "Install Directory", installPath, - "PathToExe", pathToExe, - "Program Folder Path", oldInstall.menuPath - ] - }; - var Key_uninstall = { - name: "Uninstall", - values: [ - "Description", brandFullName + " (" + app.version + ")", - "Uninstall Log Folder", installPath + "uninstall" - ] - }; - var Key_versionWithLocale = { - name: versionWithLocale, - children: [ - Key_main, - Key_uninstall - ] - }; - var Key_name = { - name: brandFullName, - values: [ - "CurrentVersion", versionWithLocale - ], - children: [ - Key_versionWithLocale - ] - }; - var Key_brand = { - name: vendorShortName, - children: [ - Key_name, - Key_nameWithVersion - ] - }; - - try { - key.open(rootKey, "SOFTWARE", key.ACCESS_READ); - createRegistryKeys(key, Key_brand); - } catch (e) {} - key.close(); - - if (rootKey != RegKey.prototype.ROOT_KEY_LOCAL_MACHINE) - return; - - // Now, do the same thing for the Add/Remove Programs control panel: - try { - key.open(rootKey, uninstallRoot, key.ACCESS_READ); - var oldName = oldInstall.fullName + " (" + oldInstall.version + ")"; - deleteRegistryKey(key, oldName, false); - } catch (e) {} - key.close(); - - var uninstallBundle = sbs.createBundle(URI_UNINSTALL_PROPERTIES); - - var nameWithVersion = brandFullName + " (" + app.version + ")"; - - var uninstaller = getFile(KEY_APPDIR); - uninstaller.append("uninstall"); - uninstaller.append("uninst.exe"); - var uninstallString = uninstaller.path; - - Key_uninstall = { - name: nameWithVersion, - values: [ - "Comment", brandFullName, - "DisplayIcon", pathToExe + ",0", // XXX don't hardcode me! - "DisplayName", nameWithVersion, - "DisplayVersion", versionWithLocale, - "InstallLocation", ourInstallDir.path, // no trailing slash - "Publisher", vendorShortName, - "UninstallString", uninstallString, - "URLInfoAbout", uninstallBundle.GetStringFromName("URLInfoAbout"), - "URLUpdateInfo", uninstallBundle.GetStringFromName("URLUpdateInfo") - ] - }; - - var child; - try { - key.open(rootKey, uninstallRoot, key.ACCESS_READ); - createRegistryKeys(key, Key_uninstall); - - // Create additional DWORD keys for NoModify and NoRepair: - child = key.openChild(nameWithVersion, key.ACCESS_WRITE); - child.writeIntValue("NoModify", 1); - child.writeIntValue("NoRepair", 1); - } catch (e) {} - if (child) - child.close(); key.close(); + return result; } //----------------------------------------------------------------------------- function nsPostUpdateWin() { + gConsole = Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService); + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. + getService(Components.interfaces.nsIPrefBranch); + try { + gAppUpdateLogPostUpdate = prefs.getBoolPref("app.update.log.all"); + } + catch (ex) { + } + try { + if (!gAppUpdateLogPostUpdate) + gAppUpdateLogPostUpdate = prefs.getBoolPref("app.update.log.PostUpdate"); + } + catch (ex) { + } } nsPostUpdateWin.prototype = { @@ -826,20 +601,66 @@ nsPostUpdateWin.prototype = { run: function() { try { - // We use a global object here for the install log writer, so that the - // registry updating code can easily inform it of registry keys that it - // may create. installLogWriter = new InstallLogWriter(); try { installLogWriter.begin(); - updateRegistry(RegKey.prototype.ROOT_KEY_CURRENT_USER); - updateRegistry(RegKey.prototype.ROOT_KEY_LOCAL_MACHINE); } finally { installLogWriter.end(); installLogWriter = null; } } catch (e) { LOG(e); + } + + var app = + Components.classes["@mozilla.org/xre/app-info;1"]. + getService(Components.interfaces.nsIXULAppInfo). + QueryInterface(Components.interfaces.nsIXULRuntime); + + var sbs = + Components.classes["@mozilla.org/intl/stringbundle;1"]. + getService(Components.interfaces.nsIStringBundleService); + var brandBundle = sbs.createBundle(URI_BRAND_PROPERTIES); + + var vendorShortName; + try { + // The Thunderbird vendorShortName is "Mozilla Thunderbird", but we + // just want "Thunderbird", so allow it to be overridden in prefs. + + var prefs = + Components.classes["@mozilla.org/preferences-service;1"]. + getService(Components.interfaces.nsIPrefBranch); + + vendorShortName = prefs.getCharPref("app.update.vendorName.override"); + } + catch (e) { + vendorShortName = brandBundle.GetStringFromName("vendorShortName"); + } + var brandFullName = brandBundle.GetStringFromName("brandFullName"); + + if (!gCopiedLog && + !checkRegistry() && + !checkOldInstall(RegKey.prototype.ROOT_KEY_LOCAL_MACHINE, + vendorShortName, brandFullName, app.version) && + !checkOldInstall(RegKey.prototype.ROOT_KEY_CURRENT_USER, + vendorShortName, brandFullName, app.version)) { + LOG("nothing to do, so don't launch the helper"); + return; + } + + try { + var winAppHelper = + app.QueryInterface(Components.interfaces.nsIWinAppHelper); + + // note, gCopiedLog could be null + if (gCopiedLog) + LOG("calling postUpdate with: " + gCopiedLog.path); + else + LOG("calling postUpdate without a log"); + + winAppHelper.postUpdate(gCopiedLog); + } catch (e) { + LOG("failed to launch the helper to do the post update cleanup: " + e); } } }; diff --git a/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in b/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in index 256eaa62aa7..bb169c34c87 100644 --- a/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in +++ b/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in @@ -65,6 +65,11 @@ const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.proper const URI_UPDATE_NS = "http://www.mozilla.org/2005/app-update"; const KEY_APPDIR = "XCurProcD"; +#ifdef XP_WIN +const KEY_LOCALDATA = "DefProfLRt"; +const KEY_PROGRAMFILES = "ProgF"; +const KEY_UAPPDATA = "UAppData"; +#endif const DIR_UPDATES = "updates"; const FILE_UPDATE_STATUS = "update.status"; @@ -180,7 +185,7 @@ function getURLSpecFromFile(file) { * parent directories that need to be created. */ function getDir(key, pathArray) { - return getDirInternal(key, pathArray, true); + return getDirInternal(key, pathArray, true, false); } /** @@ -195,7 +200,21 @@ function getDir(key, pathArray) { * requested does not exist, it is NOT created. */ function getDirNoCreate(key, pathArray) { - return getDirInternal(key, pathArray, false); + return getDirInternal(key, pathArray, false, false); +} + +/** + * Gets the specified directory at the specified hierarchy under the + * update root directory. + * @param pathArray + * An array of path components to locate beneath the directory + * specified by |key| + * @return nsIFile object for the location specified. If the directory + * requested does not exist, it is created, along with any + * parent directories that need to be created. + */ +function getUpdateDir(pathArray) { + return getDirInternal(KEY_APPDIR, pathArray, true, true); } /** @@ -210,12 +229,27 @@ function getDirNoCreate(key, pathArray) { * true if the directory hierarchy specified in |pathArray| * should be created if it does not exist, * false otherwise. + * @param update + * true if finding the update directory, + * false otherwise. * @return nsIFile object for the location specified. */ -function getDirInternal(key, pathArray, shouldCreate) { +function getDirInternal(key, pathArray, shouldCreate, update) { var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties); - var dir = fileLocator.get(key, Components.interfaces.nsIFile); + var dir = fileLocator.get(key, Components.interfaces.nsILocalFile); +#ifdef XP_WIN + if (update) { + var programFilesDir = fileLocator.get(KEY_PROGRAMFILES, + Components.interfaces.nsILocalFile); + if (programFilesDir.contains(dir, true)) { + var relativePath = dir.getRelativeDescriptor(programFilesDir); + var userLocalDir = fileLocator.get(KEY_LOCALDATA, + Components.interfaces.nsILocalFile).parent; + dir.setRelativeDescriptor(userLocalDir, relativePath); + } + } +#endif for (var i = 0; i < pathArray.length; ++i) { dir.append(pathArray[i]); if (shouldCreate && !dir.exists()) @@ -242,6 +276,22 @@ function getFile(key, pathArray) { return file; } +/** + * Gets the file at the speciifed hierarchy under the update root directory. + * @param pathArray + * An array of path components to locate beneath the directory + * specified by |key|. The last item in this array must be the + * leaf name of a file. + * @return nsIFile object for the file specified. The file is NOT created + * if it does not exist, however all required directories along + * the way are. + */ +function getUpdateFile(pathArray) { + var file = getUpdateDir(pathArray.slice(0, -1)); + file.append(pathArray[pathArray.length - 1]); + return file; +} + /** * Closes a Safe Output Stream * @param fos @@ -289,18 +339,36 @@ function getStatusTextFromCode(code, defaultCode) { /** * Get the Active Updates directory + * @param key + * The Directory Service Key (optional). + * If used, don't search local appdata on Win32 and don't create dir. * @returns The active updates directory, as a nsIFile object */ -function getUpdatesDir() { +function getUpdatesDir(key) { // Right now, we only support downloading one patch at a time, so we always // use the same target directory. var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties); - var appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsIFile); + var appDir; + if (key) + appDir = fileLocator.get(key, Components.interfaces.nsILocalFile); + else { + appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsILocalFile); +#ifdef XP_WIN + var programFilesDir = fileLocator.get(KEY_PROGRAMFILES, + Components.interfaces.nsILocalFile); + if (programFilesDir.contains(appDir, true)) { + var relativePath = appDir.getRelativeDescriptor(programFilesDir); + var userLocalDir = fileLocator.get(KEY_LOCALDATA, + Components.interfaces.nsILocalFile).parent; + appDir.setRelativeDescriptor(userLocalDir, relativePath); + } +#endif + } appDir.append(DIR_UPDATES); appDir.append("0"); - if (!appDir.exists()) + if (!appDir.exists() && !key) appDir.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY); return appDir; } @@ -337,17 +405,20 @@ function writeStatusFile(dir, state) { /** * Removes the Updates Directory + * @param key + * The Directory Service Key under which update directory resides + * (optional). */ -function cleanUpUpdatesDir() { +function cleanUpUpdatesDir(key) { // Bail out if we don't have appropriate permissions var updateDir; try { - updateDir = getUpdatesDir(); + updateDir = getUpdatesDir(key); } catch (e) { return; } - + var e = updateDir.directoryEntries; while (e.hasMoreElements()) { var f = e.getNext().QueryInterface(Components.interfaces.nsIFile); @@ -386,8 +457,11 @@ function cleanUpUpdatesDir() { /** * Clean up updates list and the updates directory. + * @param key + * The Directory Service Key under which update directory resides + * (optional). */ -function cleanupActiveUpdate() { +function cleanupActiveUpdate(key) { // Move the update from the Active Update list into the Past Updates list. var um = Components.classes["@mozilla.org/updates/update-manager;1"]. @@ -396,7 +470,7 @@ function cleanupActiveUpdate() { um.saveUpdates(); // Now trash the updates directory, since we're done with it - cleanUpUpdatesDir(); + cleanUpUpdatesDir(key); } /** @@ -1048,6 +1122,30 @@ UpdateService.prototype = { if (status == "null") status = null; + var updRootKey = null; +#ifdef XP_WIN + function findPreviousUpdate(key) { + var updateDir = getUpdatesDir(key); + if (updateDir.exists()) { + status = readStatusFile(updateDir); + // Previous download should succeed. Otherwise, we will not be here! + if (status == STATE_SUCCEEDED) + updRootKey = key; + else + status = null; + } + } + + // required when updating from Fx 2.0.0.1 to 2.0.0.3 (or later) + // on Windows Vista. + if (status == null) + findPreviousUpdate(KEY_UAPPDATA); + + // required to migrate from older versions. + if (status == null) + findPreviousUpdate(KEY_APPDIR); +#endif + if (status == STATE_DOWNLOADING) { LOG("UpdateService", "_postUpdateProcessing: Downloading patch, resuming..."); } @@ -1098,7 +1196,7 @@ UpdateService.prototype = { } // Done with this update. Clean it up. - cleanupActiveUpdate(); + cleanupActiveUpdate(updRootKey); } else { // If we hit an error, then the error code will be included in the @@ -1407,7 +1505,7 @@ UpdateService.prototype = { */ get canUpdate() { try { - var appDirFile = getFile(KEY_APPDIR, [FILE_PERMS_TEST]); + var appDirFile = getUpdateFile([FILE_PERMS_TEST]); if (!appDirFile.exists()) { appDirFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); appDirFile.remove(false); @@ -1516,8 +1614,7 @@ UpdateService.prototype = { */ function UpdateManager() { // Ensure the Active Update file is loaded - var updates = this._loadXMLFileIntoArray(getFile(KEY_APPDIR, - [FILE_UPDATE_ACTIVE])); + var updates = this._loadXMLFileIntoArray(getUpdateFile([FILE_UPDATE_ACTIVE])); if (updates.length > 0) this._activeUpdate = updates[0]; } @@ -1584,7 +1681,7 @@ UpdateManager.prototype = { */ _ensureUpdates: function() { if (!this._updates) { - this._updates = this._loadXMLFileIntoArray(getFile(KEY_APPDIR, + this._updates = this._loadXMLFileIntoArray(getUpdateFile( [FILE_UPDATES_DB])); // Make sure that any active update is part of our updates list @@ -1635,7 +1732,7 @@ UpdateManager.prototype = { } else this._writeUpdatesToXMLFile([this._activeUpdate], - getFile(KEY_APPDIR, [FILE_UPDATE_ACTIVE])); + getUpdateFile([FILE_UPDATE_ACTIVE])); return activeUpdate; }, @@ -1707,10 +1804,10 @@ UpdateManager.prototype = { */ saveUpdates: function() { this._writeUpdatesToXMLFile([this._activeUpdate], - getFile(KEY_APPDIR, [FILE_UPDATE_ACTIVE])); + getUpdateFile([FILE_UPDATE_ACTIVE])); if (this._updates) { this._writeUpdatesToXMLFile(this._updates.slice(0, 10), - getFile(KEY_APPDIR, [FILE_UPDATES_DB])); + getUpdateFile([FILE_UPDATES_DB])); } }, diff --git a/mozilla/toolkit/mozapps/update/src/updater/Makefile.in b/mozilla/toolkit/mozapps/update/src/updater/Makefile.in index 4e7d2bbefc7..78c97a91ee8 100644 --- a/mozilla/toolkit/mozapps/update/src/updater/Makefile.in +++ b/mozilla/toolkit/mozapps/update/src/updater/Makefile.in @@ -64,7 +64,7 @@ USE_STATIC_LIBS = 1 HAVE_PROGRESSUI = 1 RCINCLUDE = updater.rc CPPSRCS += progressui_win.cpp -OS_LIBS += $(call EXPAND_LIBNAME,comctl32 ws2_32) +OS_LIBS += $(call EXPAND_LIBNAME,comctl32 ws2_32 shell32) ifndef GNU_CC RCFLAGS += -I$(srcdir) else diff --git a/mozilla/toolkit/mozapps/update/src/updater/updater.cpp b/mozilla/toolkit/mozapps/update/src/updater/updater.cpp index 0da7f952e26..fab554475c4 100644 --- a/mozilla/toolkit/mozapps/update/src/updater/updater.cpp +++ b/mozilla/toolkit/mozapps/update/src/updater/updater.cpp @@ -1022,7 +1022,7 @@ LaunchCallbackApp(const char *workingDir, int argc, char **argv) #elif defined(XP_MACOSX) LaunchChild(argc, argv); #elif defined(XP_WIN) - WinLaunchChild(argv[0], argc, argv); + WinLaunchChild(argv[0], argc, argv, -1); #else # warning "Need implementaton of LaunchCallbackApp" #endif @@ -1200,8 +1200,10 @@ ActionList::Prepare() // If the action list is empty then we should fail in order to signal that // something has gone wrong. Otherwise we report success when nothing is // actually done. See bug 327140. - if (mCount == 0) + if (mCount == 0) { + LOG(("empty action list\n")); return UNEXPECTED_ERROR; + } Action *a = mFirst; while (a) { diff --git a/mozilla/toolkit/xre/Makefile.in b/mozilla/toolkit/xre/Makefile.in index 7df5f91df20..fe21b903fc2 100644 --- a/mozilla/toolkit/xre/Makefile.in +++ b/mozilla/toolkit/xre/Makefile.in @@ -96,6 +96,10 @@ XPIDLSRCS = \ nsIXULRuntime.idl \ $(NULL) +ifeq ($(OS_ARCH),WINNT) +XPIDLSRCS += nsIWinAppHelper.idl +endif + EXPORTS = \ xrecore.h \ nsXULAppAPI.h \ diff --git a/mozilla/toolkit/xre/nsAppRunner.cpp b/mozilla/toolkit/xre/nsAppRunner.cpp index 362e60c4a87..721f1f86896 100644 --- a/mozilla/toolkit/xre/nsAppRunner.cpp +++ b/mozilla/toolkit/xre/nsAppRunner.cpp @@ -98,6 +98,9 @@ #include "nsIWindowWatcher.h" #include "nsIXULAppInfo.h" #include "nsIXULRuntime.h" +#ifdef XP_WIN +#include "nsIWinAppHelper.h" +#endif #include "nsCRT.h" #include "nsCOMPtr.h" @@ -138,6 +141,8 @@ #ifdef XP_WIN #include +#include +#include "nsThreadUtils.h" #endif #ifdef XP_OS2 @@ -407,6 +412,75 @@ CheckArg(const char* aArg, const char **aParam = nsnull) return ARG_NONE; } +#if defined(XP_WIN) +/** + * Check for a commandline flag from the windows shell and remove it from the + * argv used when restarting. Flags MUST be in the form -arg. + * + * @param aArg the parameter to check. Must be lowercase. + */ +static ArgResult +CheckArgShell(const char* aArg) +{ + char **curarg = gRestartArgv + 1; // skip argv[0] + + while (*curarg) { + char *arg = curarg[0]; + + if (arg[0] == '-') { + ++arg; + + if (strimatch(aArg, arg)) { + do { + *curarg = *(curarg + 1); + ++curarg; + } while (*curarg); + + --gRestartArgc; + + return ARG_FOUND; + } + } + + ++curarg; + } + + return ARG_NONE; +} + +/** + * Spins up Windows DDE when the app needs to restart or the profile manager + * will be displayed during startup and the app has been launched by the Windows + * shell to open an url. This prevents Windows from displaying an error message + * due to the DDE message not being acknowledged. + */ +static void +ProcessDDE(nsINativeAppSupport* aNative) +{ + // When the app is launched by the windows shell the windows shell + // expects the app to be available for DDE messages and if it isn't + // windows displays an error dialog. To prevent the error the DDE server + // is enabled and pending events are processed when the app needs to + // restart after it was launched by the shell with the requestpending + // argument. The requestpending pending argument is removed to + // differentiate it from being launched when an app restart is not + // required. + ArgResult ar; + ar = CheckArgShell("requestpending"); + if (ar == ARG_FOUND) { + aNative->Enable(); // enable win32 DDE responses + nsIThread *thread = NS_GetCurrentThread(); + // This is just a guesstimate based on testing different values. + // If count is 8 or less windows will display an error dialog. + PRInt32 count = 20; + while(--count >= 0) { + NS_ProcessNextEvent(thread); + PR_Sleep(PR_MillisecondsToInterval(1)); + } + } +} +#endif + PRBool gSafeMode = PR_FALSE; /** @@ -414,17 +488,29 @@ PRBool gSafeMode = PR_FALSE; * singleton. */ class nsXULAppInfo : public nsIXULAppInfo, +#ifdef XP_WIN + public nsIWinAppHelper, +#endif public nsIXULRuntime + { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIXULAPPINFO NS_DECL_NSIXULRUNTIME +#ifdef XP_WIN + NS_DECL_NSIWINAPPHELPER +private: + nsresult LaunchAppHelperWithArgs(int aArgc, char **aArgv); +#endif }; NS_INTERFACE_MAP_BEGIN(nsXULAppInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime) NS_INTERFACE_MAP_ENTRY(nsIXULRuntime) +#ifdef XP_WIN + NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper) +#endif NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData) NS_INTERFACE_MAP_END @@ -535,6 +621,92 @@ nsXULAppInfo::GetXPCOMABI(nsACString& aResult) #endif } +#ifdef XP_WIN +nsresult +nsXULAppInfo::LaunchAppHelperWithArgs(int aArgc, char **aArgv) +{ + nsresult rv; + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr appHelper; + rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(appHelper)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe")); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString appHelperPath; + rv = appHelper->GetNativePath(appHelperPath); + NS_ENSURE_SUCCESS(rv, rv); + + if (!WinLaunchChild(appHelperPath.get(), aArgc, aArgv, 1)) + return NS_ERROR_FAILURE; + else + return NS_OK; +} + +NS_IMETHODIMP +nsXULAppInfo::FixReg() +{ + int resetRegArgc = 2; + char **resetRegArgv = (char**) malloc(sizeof(char*) * (resetRegArgc + 1)); + if (!resetRegArgv) + return NS_ERROR_OUT_OF_MEMORY; + + resetRegArgv[0] = "argv0ignoredbywinlaunchchild"; + resetRegArgv[1] = "/fixreg"; + resetRegArgv[2] = nsnull; + nsresult rv = LaunchAppHelperWithArgs(resetRegArgc, resetRegArgv); + free(resetRegArgv); + return rv; +} + +NS_IMETHODIMP +nsXULAppInfo::PostUpdate(nsILocalFile *aLogFile) +{ + nsresult rv; + int upgradeArgc = aLogFile ? 3 : 2; + char **upgradeArgv = (char**) malloc(sizeof(char*) * (upgradeArgc + 1)); + + if (!upgradeArgv) + return NS_ERROR_OUT_OF_MEMORY; + + upgradeArgv[0] = "argv0ignoredbywinlaunchchild"; + upgradeArgv[1] = "/postupdate"; + + char *pathArg = nsnull; + + if (aLogFile) { + nsCAutoString logFilePath; + rv = aLogFile->GetNativePath(logFilePath); + NS_ENSURE_SUCCESS(rv, rv); + + pathArg = PR_smprintf("/uninstalllog=%s", logFilePath.get()); + if (!pathArg) + return NS_ERROR_OUT_OF_MEMORY; + + upgradeArgv[2] = pathArg; + upgradeArgv[3] = nsnull; + } + else { + upgradeArgv[2] = nsnull; + } + + rv = LaunchAppHelperWithArgs(upgradeArgc, upgradeArgv); + + if (pathArg) + PR_smprintf_free(pathArg); + + free(upgradeArgv); + return rv; +} +#endif + static const nsXULAppInfo kAppInfo; static NS_METHOD AppInfoConstructor(nsISupports* aOuter, REFNSIID aIID, void **aResult) @@ -1199,6 +1371,27 @@ XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult) return NS_OK; } +// copied from nsXREDirProvider.cpp +#ifdef XP_WIN +static nsresult +GetShellFolderPath(int folder, char result[MAXPATHLEN]) +{ + LPITEMIDLIST pItemIDList = NULL; + + nsresult rv; + if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, folder, &pItemIDList)) && + SUCCEEDED(SHGetPathFromIDList(pItemIDList, result))) { + rv = NS_OK; + } else { + rv = NS_ERROR_NOT_AVAILABLE; + } + + CoTaskMemFree(pItemIDList); + + return rv; +} +#endif + #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200) #ifdef XP_WIN @@ -1237,7 +1430,7 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative, return rv; #if defined(XP_WIN) - if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv)) + if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, 0)) return NS_ERROR_FAILURE; #elif defined(XP_OS2) if (_execv(exePath.get(), gRestartArgv) == -1) @@ -1369,6 +1562,10 @@ ShowProfileManager(nsIToolkitProfileService* aProfileSvc, SetupMacCommandLine(gRestartArgc, gRestartArgv); #endif +#ifdef XP_WIN + ProcessDDE(aNative); +#endif + { //extra scoping is needed so we release these components before xpcom shutdown nsCOMPtr windowWatcher (do_GetService(NS_WINDOWWATCHER_CONTRACTID)); @@ -2251,8 +2448,45 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) #if defined(MOZ_UPDATER) // Check for and process any available updates + nsCOMPtr updRoot = dirProvider.GetAppDir(); + nsCOMPtr updRootl(do_QueryInterface(updRoot)); + +#ifdef XP_WIN + // Use \updates\ if app dir is under Program Files to avoid the + // folder virtualization mess on Windows Vista + char path[MAXPATHLEN]; + rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, path); + NS_ENSURE_SUCCESS(rv, 1); + nsCOMPtr programFilesDir; + rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_FALSE, + getter_AddRefs(programFilesDir)); + NS_ENSURE_SUCCESS(rv, 1); + + PRBool descendant; + rv = programFilesDir->Contains(updRootl, PR_TRUE, &descendant); + NS_ENSURE_SUCCESS(rv, 1); + if (descendant) { + nsCAutoString relativePath; + rv = updRootl->GetRelativeDescriptor(programFilesDir, relativePath); + NS_ENSURE_SUCCESS(rv, 1); + + nsCOMPtr userLocalDir; + rv = dirProvider.GetUserLocalDataDirectory(getter_AddRefs(userLocalDir)); + NS_ENSURE_SUCCESS(rv, 1); + + rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, + getter_AddRefs(updRootl)); + NS_ENSURE_SUCCESS(rv, 1); + + rv = updRootl->SetRelativeDescriptor(userLocalDir, relativePath); + NS_ENSURE_SUCCESS(rv, 1); + } +#endif + ProcessUpdates(dirProvider.GetGREDir(), dirProvider.GetAppDir(), + updRootl, gRestartArgc, gRestartArgv); #endif @@ -2543,6 +2777,10 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) // registry - major milestone vs. build id. needsRestart = PR_TRUE; +#ifdef XP_WIN + ProcessDDE(nativeApp); +#endif + #ifdef XP_MACOSX SetupMacCommandLine(gRestartArgc, gRestartArgv); #endif diff --git a/mozilla/toolkit/xre/nsAppRunner.h b/mozilla/toolkit/xre/nsAppRunner.h index 0982dea2261..75436fd6e73 100644 --- a/mozilla/toolkit/xre/nsAppRunner.h +++ b/mozilla/toolkit/xre/nsAppRunner.h @@ -119,7 +119,7 @@ WriteConsoleLog(); #ifdef XP_WIN BOOL -WinLaunchChild(const char *exePath, int argc, char **argv); +WinLaunchChild(const char *exePath, int argc, char **argv, int needElevation); #endif #define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1" diff --git a/mozilla/toolkit/xre/nsIWinAppHelper.idl b/mozilla/toolkit/xre/nsIWinAppHelper.idl new file mode 100644 index 00000000000..968a5bf12dc --- /dev/null +++ b/mozilla/toolkit/xre/nsIWinAppHelper.idl @@ -0,0 +1,54 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is post update cleanup + * + * The Initial Developer of the Original Code is + * Seth Spitzer + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * A scriptable interface used on Windows only to do some work from + * a special process that gets created with elevated privileges. + * + * @status UNSTABLE - This interface is not frozen and will probably change in + * future releases. + */ + +interface nsILocalFile; + +[scriptable, uuid(575249a7-de7a-4602-a997-b7ad2b3b6dab)] +interface nsIWinAppHelper : nsISupports +{ + void postUpdate(in nsILocalFile logFile); + void fixReg(); +}; diff --git a/mozilla/toolkit/xre/nsNativeAppSupportWin.cpp b/mozilla/toolkit/xre/nsNativeAppSupportWin.cpp index b93c1d905ae..81ccd9ed522 100644 --- a/mozilla/toolkit/xre/nsNativeAppSupportWin.cpp +++ b/mozilla/toolkit/xre/nsNativeAppSupportWin.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Bill Law law@netscape.com + * Robert Strong robert.bugzilla@gmail.com * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -256,10 +257,10 @@ private: * whether Mozilla is already running. */ -/* Update 2006 September +/* Update 2007 January * * A change in behavior was implemented in July 2004 which made the - * application add on launch and remove on quit the ddexec registry key. + * application on launch to add and on quit to remove the ddexec registry key. * See bug 246078. * Windows Vista has changed the methods used to set an application as default * and the new methods are incompatible with removing the ddeexec registry key. @@ -280,21 +281,20 @@ private: * for the verb (e.g. open). * * Application DDE Sequence: - * 1. If the application is running a DDE request is received DDE with the + * 1. If the application is running a DDE request is received with the * WWW_OpenURL topic and the params as specified in the default value of the * ddeexec registry key (e.g. "%1",,0,0,,,, where '%1' is the url to open) * for the verb (e.g. open). - * 2. If the application is not running it is launched with the -url argument. + * 2. If the application is not running it is launched with the -requestPending + * and the -url argument. + * 2.1 If the application does not need to restart and the -requestPending + * argument is present the accompanying url will not be used. Instead the + * application will wait for the DDE message to open the url. + * 2.2 If the application needs to restart the -requestPending argument is + * removed from the arguments used to restart the application and the url + * will be handled normally. * - * Note: Typically the application should use the DDE request to open the page - * instead of using a command line argument. The command line argument is - * used to work around when the DDE queue is hung by a different - * application. See bug 53952. - * - * 3. The application receives a DDE request with the WWW_OpenURL topic and the - * params from the ifexec key without the url (e.g. ,,0,0,,,,). The - * application treats this request as a noop internally and returns the - * correct values for the DDE request to the OS. + * Note: Due to a bug in IE the ifexec key should not be used (see bug 355650). */ class nsNativeAppSupportWin : public nsNativeAppSupportBase, @@ -457,6 +457,7 @@ NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) { // Constants #define MOZ_DDE_APPLICATION "Mozilla" +#define MOZ_MUTEX_NAMESPACE "Local\\" #define MOZ_STARTUP_MUTEX_NAME "StartupMutex" #define MOZ_DDE_START_TIMEOUT 30000 #define MOZ_DDE_STOP_TIMEOUT 15000 @@ -677,7 +678,8 @@ nsNativeAppSupportWin::Start( PRBool *aResult ) { // Grab mutex first. // Build mutex name from app name. - ::_snprintf( mMutexName, sizeof mMutexName, "%s%s", gAppData->name, MOZ_STARTUP_MUTEX_NAME ); + ::_snprintf( mMutexName, sizeof mMutexName, "%s%s%s", MOZ_MUTEX_NAMESPACE, + gAppData->name, MOZ_STARTUP_MUTEX_NAME ); Mutex startupLock = Mutex( mMutexName ); NS_ENSURE_TRUE( startupLock.Lock( MOZ_DDE_START_TIMEOUT ), NS_ERROR_FAILURE ); @@ -835,6 +837,9 @@ nsNativeAppSupportWin::Quit() { } DdeUninitialize( mInstance ); mInstance = 0; +#if MOZ_DEBUG_DDE + printf( "DDE server stopped\n" ); +#endif } return NS_OK; @@ -978,25 +983,23 @@ nsNativeAppSupportWin::HandleDDENotification( UINT uType, // transaction t nsCAutoString url; ParseDDEArg(hsz2, 0, url); - if ( !url.Equals( "" ) ) { - // Read the 3rd argument in the command to determine if a - // new window is to be used. - nsCAutoString windowID; - ParseDDEArg(hsz2, 2, windowID); - // "" means to open the URL in a new window. - if ( windowID.Equals( "" ) ) { - url.Insert("mozilla -new-window ", 0); - } - else { - url.Insert("mozilla -url ", 0); - } + // Read the 3rd argument in the command to determine if a + // new window is to be used. + nsCAutoString windowID; + ParseDDEArg(hsz2, 2, windowID); + // "" means to open the URL in a new window. + if ( windowID.Equals( "" ) ) { + url.Insert("mozilla -new-window ", 0); + } + else { + url.Insert("mozilla -url ", 0); + } #if MOZ_DEBUG_DDE - printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() ); + printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() ); #endif - // Now handle it. - HandleCommandLine(url.get(), nsnull, nsICommandLine::STATE_REMOTE_EXPLICIT); - } + // Now handle it. + HandleCommandLine(url.get(), nsnull, nsICommandLine::STATE_REMOTE_EXPLICIT); // Return pseudo window ID. result = CreateDDEData( 1 ); @@ -1151,25 +1154,23 @@ nsNativeAppSupportWin::HandleDDENotification( UINT uType, // transaction t nsCAutoString url; ParseDDEArg((const char*) request, 0, url); - if ( !url.Equals( "" ) ) { - // Read the 3rd argument in the command to determine if a - // new window is to be used. - nsCAutoString windowID; - ParseDDEArg((const char*) request, 2, windowID); + // Read the 3rd argument in the command to determine if a + // new window is to be used. + nsCAutoString windowID; + ParseDDEArg((const char*) request, 2, windowID); - // "" means to open the URL in a new window. - if ( windowID.Equals( "" ) ) { - url.Insert("mozilla -new-window ", 0); - } - else { - url.Insert("mozilla -url ", 0); - } -#if MOZ_DEBUG_DDE - printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() ); -#endif - // Now handle it. - HandleCommandLine(url.get(), nsnull, nsICommandLine::STATE_REMOTE_EXPLICIT); + // "" means to open the URL in a new window. + if ( windowID.Equals( "" ) ) { + url.Insert("mozilla -new-window ", 0); } + else { + url.Insert("mozilla -url ", 0); + } +#if MOZ_DEBUG_DDE + printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() ); +#endif + // Now handle it. + HandleCommandLine(url.get(), nsnull, nsICommandLine::STATE_REMOTE_EXPLICIT); // Release the data. DdeUnaccessData( hdata ); diff --git a/mozilla/toolkit/xre/nsUpdateDriver.cpp b/mozilla/toolkit/xre/nsUpdateDriver.cpp index c88af830fcb..f1d5c0a84d4 100644 --- a/mozilla/toolkit/xre/nsUpdateDriver.cpp +++ b/mozilla/toolkit/xre/nsUpdateDriver.cpp @@ -435,7 +435,7 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile, #elif defined(XP_WIN) _chdir(applyToDir.get()); - if (!WinLaunchChild(updaterPath.get(), appArgc + 4, argv)) + if (!WinLaunchChild(updaterPath.get(), appArgc + 4, argv, 1)) return; _exit(0); #else @@ -464,12 +464,13 @@ end: } nsresult -ProcessUpdates(nsIFile *greDir, nsIFile *appDir, int argc, char **argv) +ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, + int argc, char **argv) { nsresult rv; nsCOMPtr updatesDir; - rv = appDir->Clone(getter_AddRefs(updatesDir)); + rv = updRootDir->Clone(getter_AddRefs(updatesDir)); if (NS_FAILED(rv)) return rv; rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("updates")); diff --git a/mozilla/toolkit/xre/nsUpdateDriver.h b/mozilla/toolkit/xre/nsUpdateDriver.h index 0bffe70c4f4..2382ca86cd4 100644 --- a/mozilla/toolkit/xre/nsUpdateDriver.h +++ b/mozilla/toolkit/xre/nsUpdateDriver.h @@ -58,6 +58,7 @@ class nsIFile; * This function does not modify appDir. */ NS_HIDDEN_(nsresult) ProcessUpdates(nsIFile *greDir, nsIFile *appDir, + nsIFile *updRootDir, int argc, char **argv); #endif // nsUpdateDriver_h__ diff --git a/mozilla/toolkit/xre/nsWindowsRestart.cpp b/mozilla/toolkit/xre/nsWindowsRestart.cpp index dd3bd29ba5f..7c435bfa0f1 100755 --- a/mozilla/toolkit/xre/nsWindowsRestart.cpp +++ b/mozilla/toolkit/xre/nsWindowsRestart.cpp @@ -44,6 +44,24 @@ #define nsWindowsRestart_cpp #endif +#include + +#ifndef ERROR_ELEVATION_REQUIRED +#define ERROR_ELEVATION_REQUIRED 740L +#endif + +BOOL (WINAPI *pCreateProcessWithTokenW)(HANDLE, + DWORD, + LPCWSTR, + LPWSTR, + DWORD, + LPVOID, + LPCWSTR, + LPSTARTUPINFOW, + LPPROCESS_INFORMATION); + +BOOL (WINAPI *pIsUserAnAdmin)(VOID); + /** * Get the length that the string will take when it is quoted. */ @@ -117,37 +135,159 @@ MakeCommandLine(int argc, char **argv) return s; } +/** + * alloc and convert multibyte char to unicode char + */ +static PRUnichar * +AllocConvertAToW(const char *buf) +{ + PRUint32 inputLen = strlen(buf) + 1; + int n = MultiByteToWideChar(CP_ACP, 0, buf, inputLen, NULL, 0); + if (n <= 0) + return NULL; + PRUnichar *result = (PRUnichar *)malloc(n * sizeof(PRUnichar)); + if (!result) + return NULL; + MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, n); + return result; +} + +/** + * Launch a child process without elevated privilege. + */ +static BOOL +LaunchAsNormalUser(const char *exePath, char *cl) +{ + if (!pCreateProcessWithTokenW) { + // IsUserAnAdmin is not present on Win9x and not exported by name on Win2k + *(FARPROC *)&pIsUserAnAdmin = + GetProcAddress(GetModuleHandle("shell32.dll"), "IsUserAnAdmin"); + + // CreateProcessWithTokenW is not present on WinXP or earlier + *(FARPROC *)&pCreateProcessWithTokenW = + GetProcAddress(GetModuleHandle("advapi32.dll"), + "CreateProcessWithTokenW"); + + if (!pCreateProcessWithTokenW) + return FALSE; + } + + // do nothing here if we are not elevated or IsUserAnAdmin is not present. + if (!pIsUserAnAdmin || pIsUserAnAdmin && !pIsUserAnAdmin()) + return FALSE; + + // borrow the shell token to drop the privilege + HWND hwndShell = FindWindow("Progman", NULL); + DWORD dwProcessId; + GetWindowThreadProcessId(hwndShell, &dwProcessId); + + HANDLE hProcessShell = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId); + if (!hProcessShell) + return FALSE; + + HANDLE hTokenShell; + BOOL ok = OpenProcessToken(hProcessShell, MAXIMUM_ALLOWED, &hTokenShell); + CloseHandle(hProcessShell); + if (!ok) + return FALSE; + + HANDLE hNewToken; + ok = DuplicateTokenEx(hTokenShell, + MAXIMUM_ALLOWED, + NULL, + SecurityDelegation, + TokenPrimary, + &hNewToken); + CloseHandle(hTokenShell); + if (!ok) + return FALSE; + + STARTUPINFOW si = {sizeof(si), 0}; + PROCESS_INFORMATION pi = {0}; + + PRUnichar *exePathW = AllocConvertAToW(exePath); + PRUnichar *clW = AllocConvertAToW(cl); + ok = exePathW && clW; + if (ok) { + ok = pCreateProcessWithTokenW(hNewToken, + 0, // profile is already loaded + exePathW, + clW, + 0, // No special process creation flags + NULL, // inherit my environment + NULL, // use my current directory + &si, + &pi); + } + free(exePathW); + free(clW); + CloseHandle(hNewToken); + if (!ok) + return FALSE; + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return TRUE; +} + /** * Launch a child process with the specified arguments. + * @param needElevation 1:need elevation, -1:want to drop priv, 0:don't care * @note argv[0] is ignored */ BOOL -WinLaunchChild(const char *exePath, int argc, char **argv) +WinLaunchChild(const char *exePath, int argc, char **argv, int needElevation) { - char *cl = MakeCommandLine(argc, argv); + char *cl; + BOOL ok; + if (needElevation > 0) { + cl = MakeCommandLine(argc - 1, argv + 1); + if (!cl) + return FALSE; + ok = ShellExecute(NULL, // no special UI window + NULL, // use default verb + exePath, + cl, + NULL, // use my current directory + SW_SHOWDEFAULT) > (HINSTANCE)32; + free(cl); + return ok; + } + + cl = MakeCommandLine(argc, argv); if (!cl) return FALSE; - STARTUPINFO si = {sizeof(si), 0}; - PROCESS_INFORMATION pi = {0}; + if (needElevation < 0) { + // try to launch as a normal user first + ok = LaunchAsNormalUser(exePath, cl); + // if it fails, fallback to normal launching + if (!ok) + needElevation = 0; + } + if (needElevation == 0) { + STARTUPINFO si = {sizeof(si), 0}; + PROCESS_INFORMATION pi = {0}; - BOOL ok = CreateProcess(exePath, - cl, - NULL, // no special security attributes - NULL, // no special thread attributes - FALSE, // don't inherit filehandles - 0, // No special process creation flags - NULL, // inherit my environment - NULL, // use my current directory - &si, - &pi); + ok = CreateProcess(exePath, + cl, + NULL, // no special security attributes + NULL, // no special thread attributes + FALSE, // don't inherit filehandles + 0, // No special process creation flags + NULL, // inherit my environment + NULL, // use my current directory + &si, + &pi); + + if (ok) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } free(cl); - if (ok) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - return ok; }