summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-13 23:53:48 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-13 23:53:48 +0000
commitc9bb06f4cee992d31f97ee893663a476d4efba0c (patch)
tree47bd85ad04594bfb9f1f3399b1de68e5500fd77c
parent3d59e8c708383943f572e11e5d833c3d6b10a81b (diff)
downloadchromium_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.cc2
-rw-r--r--base/win_util.cc8
-rw-r--r--base/win_util.h5
-rw-r--r--chrome/browser/browser_init.cc5
-rw-r--r--chrome/browser/shell_integration.h4
-rw-r--r--chrome/browser/shell_integration_win.cc205
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());
+}