Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: chrome/browser/shell_integration_win.cc

Issue 14027008: Migrate app_host.exe shortcuts to chrome.exe shortcuts (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rework Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/shell_integration.h" 5 #include "chrome/browser/shell_integration.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <shobjidl.h> 8 #include <shobjidl.h>
9 #include <propkey.h> 9 #include <propkey.h>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/message_loop.h" 14 #include "base/message_loop.h"
15 #include "base/path_service.h" 15 #include "base/path_service.h"
16 #include "base/string_util.h" 16 #include "base/string_util.h"
17 #include "base/stringprintf.h" 17 #include "base/stringprintf.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
20 #include "base/win/registry.h" 20 #include "base/win/registry.h"
21 #include "base/win/scoped_comptr.h" 21 #include "base/win/scoped_comptr.h"
22 #include "base/win/scoped_propvariant.h" 22 #include "base/win/scoped_propvariant.h"
23 #include "base/win/shortcut.h" 23 #include "base/win/shortcut.h"
24 #include "base/win/windows_version.h" 24 #include "base/win/windows_version.h"
25 #include "chrome/browser/web_applications/web_app.h" 25 #include "chrome/browser/web_applications/web_app.h"
26 #include "chrome/common/chrome_constants.h" 26 #include "chrome/common/chrome_constants.h"
27 #include "chrome/common/chrome_paths_internal.h" 27 #include "chrome/common/chrome_paths_internal.h"
28 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/installer/launcher_support/chrome_launcher_support.h"
29 #include "chrome/installer/setup/setup_util.h" 30 #include "chrome/installer/setup/setup_util.h"
30 #include "chrome/installer/util/browser_distribution.h" 31 #include "chrome/installer/util/browser_distribution.h"
31 #include "chrome/installer/util/create_reg_key_work_item.h" 32 #include "chrome/installer/util/create_reg_key_work_item.h"
32 #include "chrome/installer/util/install_util.h" 33 #include "chrome/installer/util/install_util.h"
33 #include "chrome/installer/util/set_reg_value_work_item.h" 34 #include "chrome/installer/util/set_reg_value_work_item.h"
34 #include "chrome/installer/util/shell_util.h" 35 #include "chrome/installer/util/shell_util.h"
35 #include "chrome/installer/util/util_constants.h" 36 #include "chrome/installer/util/util_constants.h"
36 #include "chrome/installer/util/work_item.h" 37 #include "chrome/installer/util/work_item.h"
37 #include "chrome/installer/util/work_item_list.h" 38 #include "chrome/installer/util/work_item_list.h"
38 #include "content/public/browser/browser_thread.h" 39 #include "content/public/browser/browser_thread.h"
39 40
40 using content::BrowserThread; 41 using content::BrowserThread;
41 42
42 namespace { 43 namespace {
43 44
44 const wchar_t kAppListAppNameSuffix[] = L"AppList"; 45 const wchar_t kAppListAppNameSuffix[] = L"AppList";
45 46
47 // How many seconds to delay migrating app host shortcuts.
48 const int64 kMigrateAppHostShortcutsDelaySeconds = 15;
huangs 2013/04/19 15:21:28 This appears unused.
49
46 // Helper function for ShellIntegration::GetAppId to generates profile id 50 // Helper function for ShellIntegration::GetAppId to generates profile id
47 // from profile path. "profile_id" is composed of sanitized basenames of 51 // from profile path. "profile_id" is composed of sanitized basenames of
48 // user data dir and profile dir joined by a ".". 52 // user data dir and profile dir joined by a ".".
49 string16 GetProfileIdFromPath(const base::FilePath& profile_path) { 53 string16 GetProfileIdFromPath(const base::FilePath& profile_path) {
50 // Return empty string if profile_path is empty 54 // Return empty string if profile_path is empty
51 if (profile_path.empty()) 55 if (profile_path.empty())
52 return string16(); 56 return string16();
53 57
54 base::FilePath default_user_data_dir; 58 base::FilePath default_user_data_dir;
55 // Return empty string if profile_path is in default user data 59 // Return empty string if profile_path is in default user data
(...skipping 27 matching lines...) Expand all
83 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 87 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
84 string16 app_name(dist->GetBaseAppId()); 88 string16 app_name(dist->GetBaseAppId());
85 app_name.append(kAppListAppNameSuffix); 89 app_name.append(kAppListAppNameSuffix);
86 return app_name; 90 return app_name;
87 } 91 }
88 92
89 // Gets expected app id for given Chrome (based on |command_line| and 93 // Gets expected app id for given Chrome (based on |command_line| and
90 // |is_per_user_install|). 94 // |is_per_user_install|).
91 string16 GetExpectedAppId(const CommandLine& command_line, 95 string16 GetExpectedAppId(const CommandLine& command_line,
92 bool is_per_user_install) { 96 bool is_per_user_install) {
93 base::FilePath profile_path; 97 base::FilePath user_data_dir;
94 if (command_line.HasSwitch(switches::kUserDataDir)) { 98 chrome::GetDefaultUserDataDirectory(&user_data_dir);
95 profile_path = 99 if (command_line.HasSwitch(switches::kUserDataDir))
96 command_line.GetSwitchValuePath(switches::kUserDataDir).AppendASCII( 100 user_data_dir = command_line.GetSwitchValuePath(switches::kUserDataDir);
97 chrome::kInitialProfile); 101
98 } 102 base::FilePath profile_subdir;
103 profile_subdir.AppendASCII(chrome::kInitialProfile);
104 if (command_line.HasSwitch(switches::kProfileDirectory))
105 profile_subdir =
106 command_line.GetSwitchValuePath(switches::kProfileDirectory);
107
108 base::FilePath profile_path = user_data_dir.Append(profile_subdir);
99 109
100 string16 app_name; 110 string16 app_name;
101 if (command_line.HasSwitch(switches::kApp)) { 111 if (command_line.HasSwitch(switches::kApp)) {
102 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromURL( 112 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromURL(
103 GURL(command_line.GetSwitchValueASCII(switches::kApp)))); 113 GURL(command_line.GetSwitchValueASCII(switches::kApp))));
104 } else if (command_line.HasSwitch(switches::kAppId)) { 114 } else if (command_line.HasSwitch(switches::kAppId)) {
105 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId( 115 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId(
106 command_line.GetSwitchValueASCII(switches::kAppId))); 116 command_line.GetSwitchValueASCII(switches::kAppId)));
107 } else if (command_line.HasSwitch(switches::kShowAppList)) { 117 } else if (command_line.HasSwitch(switches::kShowAppList)) {
108 app_name = GetAppListAppName(); 118 app_name = GetAppListAppName();
109 } else { 119 } else {
110 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 120 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
111 app_name = ShellUtil::GetBrowserModelId(dist, is_per_user_install); 121 app_name = ShellUtil::GetBrowserModelId(dist, is_per_user_install);
112 } 122 }
113 123
114 return ShellIntegration::GetAppModelIdForProfile(app_name, profile_path); 124 return ShellIntegration::GetAppModelIdForProfile(app_name, profile_path);
115 } 125 }
116 126
117 void MigrateChromiumShortcutsCallback() { 127 // Locations to check for shortcuts migration.
128 static const struct {
129 int location_id;
130 const wchar_t* sub_dir;
131 } kLocations[] = {
132 {
133 base::DIR_IMPLICIT_APP_SHORTCUTS,
134 NULL
135 }, {
136 base::DIR_TASKBAR_PINS,
137 NULL
138 }, {
139 base::DIR_USER_DESKTOP,
140 NULL
141 }, {
142 base::DIR_START_MENU,
143 NULL
144 }, {
145 base::DIR_APP_DATA,
146 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
147 }
148 };
149
150 void MigrateShortcutsCallback() {
151 ShellIntegration::MigrateAppHostShortcuts();
152 ShellIntegration::MigrateChromiumShortcuts();
153 }
154
155 void MigrateAppHostShortcutsCallback() {
118 // This should run on the file thread. 156 // This should run on the file thread.
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
120 158
121 // Get full path of chrome. 159 // Get full path of chrome.
122 base::FilePath chrome_exe; 160 base::FilePath chrome_exe;
123 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) 161 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
124 return; 162 return;
125 163
126 // Locations to check for shortcuts migration. 164 // Get the app_host.exe path.
127 static const struct { 165 bool is_per_user_install =
128 int location_id; 166 InstallUtil::IsPerUserInstall(chrome_exe.value().c_str());
129 const wchar_t* sub_dir; 167 base::FilePath app_host_exe = GetAppHostPathForInstallationLevel(
huangs 2013/04/19 15:21:28 Does this code account for the case: 1. Chrome is
130 } kLocations[] = { 168 is_per_user_install ? chrome_launcher_support::USER_LEVEL_INSTALLATION
131 { 169 : chrome_launcher_support::SYSTEM_LEVEL_INSTALLATION);
132 base::DIR_TASKBAR_PINS,
133 NULL
134 }, {
135 base::DIR_USER_DESKTOP,
136 NULL
137 }, {
138 base::DIR_START_MENU,
139 NULL
140 }, {
141 base::DIR_APP_DATA,
142 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
143 }
144 };
145 170
146 for (int i = 0; i < arraysize(kLocations); ++i) { 171 for (int i = 0; i < arraysize(kLocations); ++i) {
147 base::FilePath path; 172 base::FilePath path;
173 if (!PathService::Get(kLocations[i].location_id, &path)) {
174 NOTREACHED();
175 continue;
176 }
177
178 if (kLocations[i].sub_dir)
179 path = path.Append(kLocations[i].sub_dir);
180
181 // Recurse when looking for user-pinned shortcuts as they exist in
182 // subdirectories.
183 bool recursive =
184 (kLocations[i].location_id == base::DIR_IMPLICIT_APP_SHORTCUTS);
185 ShellIntegration::MigrateAppHostShortcutsInPathInternal(
186 chrome_exe, app_host_exe, path, recursive);
187 }
188 }
189
190 void MigrateChromiumShortcutsCallback() {
191 // This should run on the file thread.
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
193
194 // Get full path of chrome.
195 base::FilePath chrome_exe;
196 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
197 return;
198
199 for (int i = 0; i < arraysize(kLocations); ++i) {
200 base::FilePath path;
148 if (!PathService::Get(kLocations[i].location_id, &path)) { 201 if (!PathService::Get(kLocations[i].location_id, &path)) {
149 NOTREACHED(); 202 NOTREACHED();
150 continue; 203 continue;
151 } 204 }
152 205
153 if (kLocations[i].sub_dir) 206 if (kLocations[i].sub_dir)
154 path = path.Append(kLocations[i].sub_dir); 207 path = path.Append(kLocations[i].sub_dir);
155 208
156 bool check_dual_mode = (kLocations[i].location_id == base::DIR_START_MENU); 209 bool check_dual_mode = (kLocations[i].location_id == base::DIR_START_MENU);
157 ShellIntegration::MigrateShortcutsInPathInternal(chrome_exe, path, 210 ShellIntegration::MigrateShortcutsInPathInternal(chrome_exe, path,
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 410
358 return ShellUtil::FormatIconLocation( 411 return ShellUtil::FormatIconLocation(
359 chrome_exe.value(), 412 chrome_exe.value(),
360 BrowserDistribution::GetDistribution()->GetIconIndex()); 413 BrowserDistribution::GetDistribution()->GetIconIndex());
361 } 414 }
362 415
363 void ShellIntegration::MigrateChromiumShortcuts() { 416 void ShellIntegration::MigrateChromiumShortcuts() {
364 if (base::win::GetVersion() < base::win::VERSION_WIN7) 417 if (base::win::GetVersion() < base::win::VERSION_WIN7)
365 return; 418 return;
366 419
367 // This needs to happen eventually (e.g. so that the appid is fixed and the 420 BrowserThread::PostTask(
gab 2013/04/19 18:34:50 No need for a second task here given this is alrea
368 // run-time Chrome icon is merged with the taskbar shortcut), but this is not
369 // urgent and shouldn't delay Chrome startup.
370 static const int64 kMigrateChromiumShortcutsDelaySeconds = 15;
371 BrowserThread::PostDelayedTask(
372 BrowserThread::FILE, FROM_HERE, 421 BrowserThread::FILE, FROM_HERE,
373 base::Bind(&MigrateChromiumShortcutsCallback), 422 base::Bind(&MigrateChromiumShortcutsCallback));
374 base::TimeDelta::FromSeconds(kMigrateChromiumShortcutsDelaySeconds));
375 } 423 }
376 424
377 int ShellIntegration::MigrateShortcutsInPathInternal( 425 int ShellIntegration::MigrateShortcutsInPathInternal(
378 const base::FilePath& chrome_exe, 426 const base::FilePath& chrome_exe,
379 const base::FilePath& path, 427 const base::FilePath& path,
380 bool check_dual_mode) { 428 bool check_dual_mode) {
381 DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7); 429 DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7);
382 430
383 // Enumerate all pinned shortcuts in the given path directly. 431 // Enumerate all pinned shortcuts in the given path directly.
384 file_util::FileEnumerator shortcuts_enum( 432 file_util::FileEnumerator shortcuts_enum(
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 if (updated_properties.options && 530 if (updated_properties.options &&
483 base::win::CreateOrUpdateShortcutLink( 531 base::win::CreateOrUpdateShortcutLink(
484 shortcut, updated_properties, 532 shortcut, updated_properties,
485 base::win::SHORTCUT_UPDATE_EXISTING)) { 533 base::win::SHORTCUT_UPDATE_EXISTING)) {
486 ++shortcuts_migrated; 534 ++shortcuts_migrated;
487 } 535 }
488 } 536 }
489 return shortcuts_migrated; 537 return shortcuts_migrated;
490 } 538 }
491 539
540 void ShellIntegration::MigrateShortcuts() {
541 // These migrations need to happen eventually (e.g. so that the appid is fixed
542 // and the run-time Chrome icon is merged with the taskbar shortcut), but this
543 // is not urgent and shouldn't delay Chrome startup.
544 const int64 kMigrateShortcutsDelaySeconds = 15;
545
546 BrowserThread::PostDelayedTask(
547 BrowserThread::FILE, FROM_HERE,
548 base::Bind(&MigrateShortcutsCallback),
549 base::TimeDelta::FromSeconds(kMigrateShortcutsDelaySeconds));
550 }
551
552 void ShellIntegration::MigrateAppHostShortcuts() {
553 BrowserThread::PostTask(
554 BrowserThread::FILE, FROM_HERE,
555 base::Bind(&MigrateAppHostShortcutsCallback));
556 }
557
558 int ShellIntegration::MigrateAppHostShortcutsInPathInternal(
559 const base::FilePath& chrome_exe,
560 const base::FilePath& app_host_exe,
561 const base::FilePath& path,
562 bool recursive) {
563 int shortcuts_migrated = 0;
564 base::FilePath target_path;
565 string16 arguments;
566 file_util::FileEnumerator shortcuts_enum(
567 path, recursive, file_util::FileEnumerator::FILES);
568 for (base::FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty();
569 shortcut = shortcuts_enum.Next()) {
570 // TODO(gab): Use ProgramCompare instead of comparing FilePaths below once
571 // it is fixed to work with FilePaths with spaces.
gab 2013/04/19 18:34:50 PS: This has been fixed, you can now use InstallUt
572 if (shortcut.Extension() != installer::kLnkExt ||
573 !base::win::ResolveShortcut(shortcut, &target_path, &arguments) ||
574 app_host_exe != target_path) {
575 continue;
576 }
577
578 // Any properties that need to be updated on the shortcut will be stored in
579 // |updated_properties|.
580 base::win::ShortcutProperties updated_properties;
581 updated_properties.set_target(chrome_exe);
582
583 if (base::win::CreateOrUpdateShortcutLink(
584 shortcut, updated_properties,
585 base::win::SHORTCUT_UPDATE_EXISTING)) {
586 ++shortcuts_migrated;
587 }
588 }
589 return shortcuts_migrated;
590 }
591
492 base::FilePath ShellIntegration::GetStartMenuShortcut( 592 base::FilePath ShellIntegration::GetStartMenuShortcut(
493 const base::FilePath& chrome_exe) { 593 const base::FilePath& chrome_exe) {
494 static const int kFolderIds[] = { 594 static const int kFolderIds[] = {
495 base::DIR_COMMON_START_MENU, 595 base::DIR_COMMON_START_MENU,
496 base::DIR_START_MENU, 596 base::DIR_START_MENU,
497 }; 597 };
498 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 598 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
499 string16 shortcut_name(dist->GetAppShortCutName()); 599 string16 shortcut_name(dist->GetAppShortCutName());
500 base::FilePath shortcut; 600 base::FilePath shortcut;
501 601
502 // Check both the common and the per-user Start Menu folders for system-level 602 // Check both the common and the per-user Start Menu folders for system-level
503 // installs. 603 // installs.
504 size_t folder = 604 size_t folder =
505 InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()) ? 1 : 0; 605 InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()) ? 1 : 0;
506 for (; folder < arraysize(kFolderIds); ++folder) { 606 for (; folder < arraysize(kFolderIds); ++folder) {
507 if (!PathService::Get(kFolderIds[folder], &shortcut)) { 607 if (!PathService::Get(kFolderIds[folder], &shortcut)) {
508 NOTREACHED(); 608 NOTREACHED();
509 continue; 609 continue;
510 } 610 }
511 611
512 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name + 612 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name +
513 installer::kLnkExt); 613 installer::kLnkExt);
514 if (file_util::PathExists(shortcut)) 614 if (file_util::PathExists(shortcut))
515 return shortcut; 615 return shortcut;
516 } 616 }
517 617
518 return base::FilePath(); 618 return base::FilePath();
519 } 619 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698