diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-13 23:53:48 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-13 23:53:48 +0000 |
commit | c9bb06f4cee992d31f97ee893663a476d4efba0c (patch) | |
tree | 47bd85ad04594bfb9f1f3399b1de68e5500fd77c | |
parent | 3d59e8c708383943f572e11e5d833c3d6b10a81b (diff) | |
download | chromium_src-c9bb06f4cee992d31f97ee893663a476d4efba0c.zip chromium_src-c9bb06f4cee992d31f97ee893663a476d4efba0c.tar.gz chromium_src-c9bb06f4cee992d31f97ee893663a476d4efba0c.tar.bz2 |
Ensure existing user pinned chrome shortcuts have correct app id.
On Win7, check if user has pinned chrome shortcuts and ensure they have correct app id.
BUG=28104
TEST=On Win7, install chrome prior 4.0.266.0 and pin chrome shortcut (browser with default profile, browser with non-default profile, web apps etc). Then update to a version with this fix. After update, running chrome should not have duplicate icon spawned.
Review URL: http://codereview.chromium.org/548008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36193 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/file_util_win.cc | 2 | ||||
-rw-r--r-- | base/win_util.cc | 8 | ||||
-rw-r--r-- | base/win_util.h | 5 | ||||
-rw-r--r-- | chrome/browser/browser_init.cc | 5 | ||||
-rw-r--r-- | chrome/browser/shell_integration.h | 4 | ||||
-rw-r--r-- | chrome/browser/shell_integration_win.cc | 205 |
6 files changed, 224 insertions, 5 deletions
diff --git a/base/file_util_win.cc b/base/file_util_win.cc index 9133e7b..e066422 100644 --- a/base/file_util_win.cc +++ b/base/file_util_win.cc @@ -354,7 +354,7 @@ bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination, if (FAILED(i_persist_file.QueryFrom(i_shell_link))) return false; - if (FAILED(i_persist_file->Load(destination, 0))) + if (FAILED(i_persist_file->Load(destination, STGM_READWRITE))) return false; if (source && FAILED(i_shell_link->SetPath(source))) diff --git a/base/win_util.cc b/base/win_util.cc index fa168d0..12cf241 100644 --- a/base/win_util.cc +++ b/base/win_util.cc @@ -21,6 +21,10 @@ namespace win_util { #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) +const PROPERTYKEY kPKEYAppUserModelID = + { { 0x9F4C2855, 0x9F79, 0x4B39, + { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, } }, 5 }; + void GetNonClientMetrics(NONCLIENTMETRICS* metrics) { DCHECK(metrics); @@ -394,10 +398,6 @@ bool SetAppIdForPropertyStore(IPropertyStore* property_store, // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx DCHECK(lstrlen(app_id) < 128 && wcschr(app_id, L' ') == NULL); - static const PROPERTYKEY kPKEYAppUserModelID = - { { 0x9F4C2855, 0x9F79, 0x4B39, - { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, } }, 5 }; - PROPVARIANT property_value; if (FAILED(InitPropVariantFromString(app_id, &property_value))) return false; diff --git a/base/win_util.h b/base/win_util.h index bc10c38..ca550cf 100644 --- a/base/win_util.h +++ b/base/win_util.h @@ -28,6 +28,11 @@ enum WinVersion { WINVERSION_WIN7 = 6, }; +// Property key for System.AppUserModel.ID. +// <http://msdn.microsoft.com/en-us/library/dd391569(VS.85).aspx> +// TODO(xiyuan): Remove this once we compile with Win7 SDK. +extern const PROPERTYKEY kPKEYAppUserModelID; + void GetNonClientMetrics(NONCLIENTMETRICS* metrics); // Returns the running version of Windows. diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc index 07addd7..6512071 100644 --- a/chrome/browser/browser_init.cc +++ b/chrome/browser/browser_init.cc @@ -485,6 +485,11 @@ bool BrowserInit::LaunchWithProfile::Launch(Profile* profile, base::EventRecorder::current()->StartPlayback(script_path); } +#if defined(OS_WIN) + if (process_startup) + ShellIntegration::MigrateChromiumShortcuts(); +#endif // defined(OS_WIN) + return true; } diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h index 5acea09..020e46d 100644 --- a/chrome/browser/shell_integration.h +++ b/chrome/browser/shell_integration.h @@ -84,6 +84,10 @@ class ShellIntegration { // Generates Win7 app id for Chromium by calling GetAppId with // chrome::kBrowserAppID as app_name. static std::wstring GetChromiumAppId(const FilePath& profile_path); + + // Migrates existing chrome shortcuts by tagging them with correct app id. + // see http://crbug.com/28104 + static void MigrateChromiumShortcuts(); #endif // defined(OS_WIN) // The current default browser UI state diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index 7bdc011..8d3a67a 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc @@ -5,6 +5,7 @@ #include "chrome/browser/shell_integration.h" #include <windows.h> +#include <propvarutil.h> #include <shlobj.h> #include <shobjidl.h> @@ -14,12 +15,16 @@ #include "base/message_loop.h" #include "base/path_service.h" #include "base/registry.h" +#include "base/scoped_comptr_win.h" #include "base/string_util.h" #include "base/task.h" #include "base/win_util.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths_internal.h" +#include "chrome/common/chrome_switches.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/create_reg_key_work_item.h" #include "chrome/installer/util/set_reg_value_work_item.h" @@ -64,6 +69,198 @@ std::wstring GetProfileIdFromPath(const FilePath& profile_path) { return profile_id; } +// Migrates existing chromium shortucts for Win7. +class MigrateChromiumShortcutsTask : public Task { + public: + MigrateChromiumShortcutsTask() { } + + virtual void Run(); + + private: + void MigrateWin7Shortcuts(); + void MigrateWin7ShortcutsInPath(const FilePath& path) const; + + // Get expected app id for given chrome shortcut. + // Returns true if the shortcut point to chrome and expected app id is + // successfully derived. + bool GetExpectedAppId(IShellLink* shell_link, + std::wstring* expected_app_id) const; + + // Get app id associated with given shortcut. + bool GetShortcutAppId(IShellLink* shell_link, std::wstring* app_id) const; + + FilePath chrome_exe_; + + DISALLOW_COPY_AND_ASSIGN(MigrateChromiumShortcutsTask); +}; + +void MigrateChromiumShortcutsTask::Run() { + // This should run on the file thread. + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + + MigrateWin7Shortcuts(); +} + +void MigrateChromiumShortcutsTask::MigrateWin7Shortcuts() { + // Get full path of chrome. + if (!PathService::Get(base::FILE_EXE, &chrome_exe_)) + return; + + // Locations to check for shortcuts migration. + static const struct { + int location_id; + const wchar_t* sub_dir; + } kLocations[] = { + { + base::DIR_APP_DATA, + L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar" + }, { + chrome::DIR_USER_DESKTOP, + NULL + }, { + base::DIR_START_MENU, + NULL + }, { + base::DIR_APP_DATA, + L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu" + } + }; + + for (int i = 0; i < arraysize(kLocations); ++i) { + FilePath path; + if (!PathService::Get(kLocations[i].location_id, &path)) { + NOTREACHED(); + continue; + } + + if (kLocations[i].sub_dir) + path = path.Append(kLocations[i].sub_dir); + + MigrateWin7ShortcutsInPath(path); + } +} + +void MigrateChromiumShortcutsTask::MigrateWin7ShortcutsInPath( + const FilePath& path) const { + // Enumerate all pinned shortcuts in the given path directly. + file_util::FileEnumerator shortcuts_enum( + path, + false, // not recursive + file_util::FileEnumerator::FILES, + FILE_PATH_LITERAL("*.lnk")); + + for (FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty(); + shortcut = shortcuts_enum.Next()) { + // Load the shortcut. + ScopedComPtr<IShellLink> shell_link; + if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER))) { + NOTREACHED(); + return; + } + + ScopedComPtr<IPersistFile> persist_file; + if (FAILED(persist_file.QueryFrom(shell_link)) || + FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) { + NOTREACHED(); + return; + } + + // Get expected app id from shortcut. + std::wstring expected_app_id; + if (!GetExpectedAppId(shell_link, &expected_app_id) || + expected_app_id.empty()) + continue; + + // Get existing app id from shortcut if any. + std::wstring existing_app_id; + GetShortcutAppId(shell_link, &existing_app_id); + + if (expected_app_id != existing_app_id) { + file_util::UpdateShortcutLink(NULL, + shortcut.value().c_str(), + NULL, + NULL, + NULL, + NULL, + 0, + expected_app_id.c_str()); + } + } +} + +bool MigrateChromiumShortcutsTask::GetExpectedAppId( + IShellLink* shell_link, + std::wstring* expected_app_id) const { + DCHECK(shell_link); + DCHECK(expected_app_id); + + expected_app_id->clear(); + + // Check if the shortcut points to chrome_exe. + std::wstring source; + if (FAILED(shell_link->GetPath(WriteInto(&source, MAX_PATH), + MAX_PATH, + NULL, + SLGP_RAWPATH)) || + lstrcmpi(chrome_exe_.value().c_str(), source.c_str())) + return false; + + std::wstring arguments; + if (FAILED(shell_link->GetArguments(WriteInto(&arguments, MAX_PATH), + MAX_PATH))) + return false; + + // Get expected app id from shortcut command line. + CommandLine command_line = CommandLine::FromString(StringPrintf( + L"\"%ls\" %ls", source.c_str(), arguments.c_str())); + + FilePath profile_path; + if (command_line.HasSwitch(switches::kUserDataDir)) { + profile_path = FilePath(command_line.GetSwitchValue( + switches::kUserDataDir)).Append(chrome::kNotSignedInProfile); + } + + std::wstring app_name; + if (command_line.HasSwitch(switches::kApp)) { + app_name = web_app::GenerateApplicationNameFromURL( + GURL(command_line.GetSwitchValueASCII(switches::kApp))); + } else { + app_name = chrome::kBrowserAppID; + } + + expected_app_id->assign(ShellIntegration::GetAppId(app_name.c_str(), + profile_path)); + return true; +} + +bool MigrateChromiumShortcutsTask::GetShortcutAppId( + IShellLink* shell_link, + std::wstring* app_id) const { + DCHECK(shell_link); + DCHECK(app_id); + + app_id->clear(); + + ScopedComPtr<IPropertyStore> property_store; + if (FAILED(property_store.QueryFrom(shell_link))) + return false; + + PROPVARIANT appid_value; + PropVariantInit(&appid_value); + if (FAILED(property_store->GetValue(win_util::kPKEYAppUserModelID, + &appid_value))) + return false; + + if (appid_value.vt == VT_LPWSTR || + appid_value.vt == VT_BSTR) + app_id->assign(appid_value.pwszVal); + + PropVariantClear(&appid_value); + return true; +} + }; bool ShellIntegration::SetAsDefaultBrowser() { @@ -207,3 +404,11 @@ std::wstring ShellIntegration::GetAppId(const wchar_t* app_name, std::wstring ShellIntegration::GetChromiumAppId(const FilePath& profile_path) { return GetAppId(chrome::kBrowserAppID, profile_path); } + +void ShellIntegration::MigrateChromiumShortcuts() { + if (win_util::GetWinVersion() < win_util::WINVERSION_WIN7) + return; + + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, new MigrateChromiumShortcutsTask()); +} |