Bug 562753 - On upgrade, update AppUserModelID for application shortcuts. r=rstrong.

This commit is contained in:
Jim Mathies 2010-05-14 19:24:50 -05:00
parent 1e97e41ca7
commit 7d84eaf6a8
7 changed files with 268 additions and 29 deletions

View File

@ -20,6 +20,7 @@
*
* Contributor(s):
* Ben Goodger <ben@mozilla.org> (Original Author)
* Jim Mathies <jmathies@mozilla.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
@ -37,7 +38,7 @@
#include "nsIShellService.idl"
[scriptable, uuid(3ee25e62-ad0f-464e-8225-c3b774137387)]
[scriptable, uuid(16e7e8da-8bef-4f41-be5f-045b2e9918e1)]
interface nsIWindowsShellService : nsIShellService
{
/**
@ -46,5 +47,11 @@ interface nsIWindowsShellService : nsIShellService
* @return The number of unread (new) mail messages for the current user.
*/
readonly attribute unsigned long unreadMailCount;
/**
* Provides the shell service an opportunity to do some Win7+ shortcut
* maintenance needed on initial startup of the browser.
*/
void shortcutMaintenance();
};

View File

@ -27,6 +27,7 @@
* Asaf Romano <mano@mozilla.com>
* Ryan Jones <sciguyryan@gmail.com>
* Paul O'Shannessy <paul@oshannessy.com>
* Jim Mathies <jmathies@mozilla.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
@ -63,6 +64,8 @@
#include "nsDirectoryServiceDefs.h"
#include "nsIWindowsRegKey.h"
#include "nsUnicharUtils.h"
#include "nsIWinTaskbar.h"
#include "nsISupportsPrimitives.h"
#include "windows.h"
#include "shellapi.h"
@ -86,6 +89,8 @@
#define REG_FAILED(val) \
(val != ERROR_SUCCESS)
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
#ifndef WINCE
NS_IMPL_ISUPPORTS2(nsWindowsShellService, nsIWindowsShellService, nsIShellService)
#else
@ -268,6 +273,127 @@ static SETTING gSettings[] = {
{ MAKE_KEY_NAME1("HTTPS", SOP), "", VAL_OPEN }
};
#if !defined(WINCE)
nsresult
GetHelperPath(nsAutoString& aPath)
{
nsresult rv;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILocalFile> 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);
return appHelper->GetPath(aPath);
}
nsresult
LaunchHelper(nsAutoString& aPath)
{
STARTUPINFOW si = {sizeof(si), 0};
PROCESS_INFORMATION pi = {0};
BOOL ok = CreateProcessW(NULL, (LPWSTR)aPath.get(), NULL, NULL,
FALSE, 0, NULL, NULL, &si, &pi);
if (!ok)
return NS_ERROR_FAILURE;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return NS_OK;
}
#endif // !defined(WINCE)
NS_IMETHODIMP
nsWindowsShellService::ShortcutMaintenance()
{
#if !defined(WINCE)
nsresult rv;
// Launch helper.exe so it can update the application user model ids on
// shortcuts in the user's taskbar and start menu. This keeps older pinned
// shortcuts grouped correctly after major updates. Note, we also do this
// through the upgrade installer script, however, this is the only place we
// have a chance to trap links created by users who do control the install/
// update process of the browser.
nsCOMPtr<nsIWinTaskbar> taskbarInfo =
do_GetService(NS_TASKBAR_CONTRACTID);
if (!taskbarInfo) // If we haven't built with win7 sdk features, this fails.
return NS_OK;
// Avoid if this isn't Win7+
PRBool isSupported = PR_FALSE;
taskbarInfo->GetAvailable(&isSupported);
if (!isSupported)
return NS_OK;
nsAutoString appId;
if (NS_FAILED(taskbarInfo->GetDefaultGroupId(appId)))
return NS_ERROR_UNEXPECTED;
NS_NAMED_LITERAL_CSTRING(prefName, "browser.taskbar.lastgroupid");
nsCOMPtr<nsIPrefService> prefs =
do_GetService(NS_PREFSERVICE_CONTRACTID);
if (!prefs)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIPrefBranch> prefBranch;
prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
if (!prefBranch)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsISupportsString> prefString;
rv = prefBranch->GetComplexValue(prefName.get(),
NS_GET_IID(nsISupportsString),
getter_AddRefs(prefString));
if (NS_SUCCEEDED(rv)) {
nsAutoString version;
prefString->GetData(version);
if (!version.IsEmpty() && version.Equals(appId)) {
// We're all good, get out of here.
return NS_OK;
}
}
// Update the version in prefs
prefString =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
prefString->SetData(appId);
rv = prefBranch->SetComplexValue(prefName.get(),
NS_GET_IID(nsISupportsString),
prefString);
if (NS_FAILED(rv)) {
NS_WARNING("Couldn't set last user model id!");
return NS_ERROR_UNEXPECTED;
}
nsAutoString appHelperPath;
if (NS_FAILED(GetHelperPath(appHelperPath)))
return NS_ERROR_UNEXPECTED;
appHelperPath.AppendLiteral(" /UpdateShortcutAppUserModelIds");
return LaunchHelper(appHelperPath);
#else
NS_NOTREACHED("ShortcutMaintenance not implemented on wince!");
return NS_OK;
#endif // !defined(WINCE)
}
#ifndef WINCE
PRBool
nsWindowsShellService::IsDefaultBrowserVista(PRBool* aIsDefaultBrowser)
@ -366,24 +492,9 @@ NS_IMETHODIMP
nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUsers)
{
#ifndef WINCE
nsresult rv;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILocalFile> 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);
nsAutoString appHelperPath;
rv = appHelper->GetPath(appHelperPath);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(GetHelperPath(appHelperPath)))
return NS_ERROR_FAILURE;
if (aForAllUsers) {
appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
@ -391,17 +502,7 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs
appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
}
STARTUPINFOW si = {sizeof(si), 0};
PROCESS_INFORMATION pi = {0};
BOOL ok = CreateProcessW(NULL, (LPWSTR)appHelperPath.get(), NULL, NULL,
FALSE, 0, NULL, NULL, &si, &pi);
if (!ok)
return NS_ERROR_FAILURE;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return LaunchHelper(appHelperPath);
#else
SETTING* settings;
SETTING* end = gSettings + sizeof(gSettings)/sizeof(SETTING);

View File

@ -101,6 +101,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "_ioService",
"@mozilla.org/network/io-service;1",
"nsIIOService");
XPCOMUtils.defineLazyServiceGetter(this, "_winShellService",
"@mozilla.org/browser/shell-service;1",
"nsIWindowsShellService");
/**
* Global functions
*/
@ -163,6 +167,11 @@ var WinTaskbarJumpList =
if (!this._initTaskbar())
return;
// Win shell shortcut maintenance. If we've gone through an update,
// this will update any pinned taskbar shortcuts. Not specific to
// jump lists, but this was a convienent place to call it.
this._shortcutMaintenance();
// Store our task list config data
this._tasks = tasksCfg;
@ -200,6 +209,10 @@ var WinTaskbarJumpList =
this._free();
},
_shortcutMaintenance: function WTBJL__maintenace() {
_winShellService.shortcutMaintenance();
},
/**
* List building
*/

View File

@ -119,6 +119,7 @@ VIAddVersionKey "OriginalFilename" "setup.exe"
!insertmacro RegCleanMain
!insertmacro RegCleanUninstall
!insertmacro SetBrandNameVars
!insertmacro UpdateShortcutAppModelIDs
!insertmacro UnloadUAC
!insertmacro WriteRegStr2
!insertmacro WriteRegDWORD2
@ -486,6 +487,9 @@ Section "-InstallEndCleanup"
${LogHeader} "Updating Uninstall Log With Previous Uninstall Log"
; Win7 taskbar and start menu link maintenance
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}"
; Refresh desktop icons
System::Call "shell32::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)"

View File

@ -83,6 +83,9 @@
${FixClassKeys}
${SetUninstallKeys}
; Win7 taskbar and start menu link maintenance
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}"
; Remove files that may be left behind by the application in the
; VirtualStore directory.
${CleanVirtualStore}

View File

@ -101,6 +101,7 @@ VIAddVersionKey "OriginalFilename" "helper.exe"
!insertmacro RegCleanMain
!insertmacro RegCleanUninstall
!insertmacro SetBrandNameVars
!insertmacro UpdateShortcutAppModelIDs
!insertmacro UnloadUAC
!insertmacro WriteRegDWORD2
!insertmacro WriteRegStr2

View File

@ -4675,7 +4675,15 @@
StrCmp "$R0" "" continue +1
; Update this user's shortcuts with the latest app user model id.
ClearErrors
${GetOptions} "$R0" "/UpdateShortcutAppUserModelIds" $R2
IfErrors hideshortcuts +1
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}"
GoTo finish
; Require elevation if the user can elevate
hideshortcuts:
ClearErrors
${GetOptions} "$R0" "/HideShortcuts" $R2
IfErrors showshortcuts +1
@ -5780,3 +5788,105 @@
${DeleteFile} "$INSTDIR\uninstall\${SHORTCUTS_LOG}"
!macroend
!define DeleteShortcutsLogFile "!insertmacro DeleteShortcutsLogFile"
################################################################################
# Macros for managing Win7 install features
/**
* Update Start Menu and Taskbar lnk files that point to the current install
* with the current application user model ID. Requires ApplicationID.
*
* @param _INSTALL_PATH
* The install path of the app
* @param _APP_ID
* The application user model ID for the current install
*/
!macro UpdateShortcutAppModelIDs
!ifndef UpdateShortcutAppModelIDs
!verbose push
!verbose ${_MOZFUNC_VERBOSE}
!define UpdateShortcutAppModelIDs "!insertmacro UpdateShortcutAppModelIDsCall"
Function UpdateShortcutAppModelIDs
ClearErrors
; stack: path, appid
Exch $R9 ; stack: $R9, appid | $R9 = path
Exch 1 ; stack: appid, $R9
Exch $R8 ; stack: $R8, $R9 | $R8 = appid
Push $R7 ; stack: $R7, $R8, $R9
Push $R6
Push $R5
Push $R4 ; stack: $R4, $R5, $R6, $R7, $R8, $R9
StrCpy $R7 "$QUICKLAUNCH\User Pinned"
ClearErrors
; $R9 = install path
; $R8 = appid
; $R7 = user pinned path
; $R6 = find handle
; $R5 = found filename
; $R4 = GetShortCutTarget result
; Taskbar links
FindFirst $R6 $R5 "$R7\TaskBar\*.lnk"
LoopTaskBar:
${If} ${FileExists} "$R7\TaskBar\$R5"
ShellLink::GetShortCutTarget "$R7\TaskBar\$R5"
Pop $R4
${If} "$R4" == "$R9" ; link path == install path
ApplicationID::Set "$R7\TaskBar\$R5" "$R8"
Pop $R4 ; pop Set result off the stack
${EndIf}
${EndIf}
ClearErrors
FindNext $R6 $R5
${Unless} ${Errors}
Goto LoopTaskBar
${EndUnless}
FindClose $R6
ClearErrors
; Start menu links
FindFirst $R6 $R5 "$R7\StartMenu\*.lnk"
LoopStartMenu:
${If} ${FileExists} "$R7\StartMenu\$R5"
ShellLink::GetShortCutTarget "$R7\StartMenu\$R5"
Pop $R4
${If} "$R4" == "$R9" ; link path == install path
ApplicationID::Set "$R7\StartMenu\$R5" "$R8"
Pop $R4 ; pop Set result off the stack
${EndIf}
${EndIf}
ClearErrors
FindNext $R6 $R5
${Unless} ${Errors}
Goto LoopStartMenu
${EndUnless}
FindClose $R6
Pop $R4 ; stack: $R5, $R6, $R7, $R8, $R9
Pop $R5 ; stack: $R6, $R7, $R8, $R9
Pop $R6 ; stack: $R7, $R8, $R9
Pop $R7 ; stack: $R8, $R9
Exch $R8 ; stack: appid, $R9 | $R8 = old $R8
Exch 1 ; stack: $R9, appid
Exch $R9 ; stack: path, appid | $R9 = old $R9
FunctionEnd
!verbose pop
!endif
!macroend
!macro UpdateShortcutAppModelIDsCall _INSTALL_PATH _APP_ID
!verbose push
!verbose ${_MOZFUNC_VERBOSE}
Push "${_APP_ID}"
Push "${_INSTALL_PATH}"
Call UpdateShortcutAppModelIDs
!verbose pop
!macroend