Index: chrome/installer/util/shell_util.cc |
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc |
index 4a60171174d5526e3b21bab49799e9406b19f4c5..c09f7b6970b05c1c70e74ac106fbf3aa694fbb34 100644 |
--- a/chrome/installer/util/shell_util.cc |
+++ b/chrome/installer/util/shell_util.cc |
@@ -1159,32 +1159,212 @@ ShellUtil::DefaultState ProbeProtocolHandlers( |
return ProbeOpenCommandHandlers(protocols, num_protocols); |
} |
-// Removes shortcut at |shortcut_path| if it is a shortcut that points to |
-// |target_exe|. If |delete_folder| is true, deletes the parent folder of |
-// the shortcut completely. Returns true if either the shortcut was deleted |
-// successfully or if the shortcut did not point to |target_exe|. |
-bool MaybeRemoveShortcutAtPath(const base::FilePath& shortcut_path, |
- const base::FilePath& target_exe, |
- bool delete_folder) { |
- base::FilePath target_path; |
- if (!base::win::ResolveShortcut(shortcut_path, &target_path, NULL)) |
+// (Windows 8+) Returns the folder for app shortcuts, or empty if none found. |
+base::FilePath GetAppShortcutsFolder(BrowserDistribution* dist, |
+ const string16& target_exe) { |
+ if (base::win::GetVersion() < base::win::VERSION_WIN8) |
+ return base::FilePath(); |
+ |
+ base::FilePath folder; |
+ if (!PathService::Get(base::DIR_APP_SHORTCUTS, &folder)) { |
+ LOG(ERROR) << "Could not get application shortcuts location."; |
+ return base::FilePath(); |
+ } |
+ |
+ folder = folder.Append( |
+ ShellUtil::GetBrowserModelId(dist, |
gab
2013/04/24 21:41:46
nit: wrap |dist| on the line below.
The rule is e
huangs
2013/04/25 16:27:46
Done.
|
+ InstallUtil::IsPerUserInstall(target_exe.c_str()))); |
+ if (!file_util::DirectoryExists(folder)) { |
+ VLOG(1) << "No start screen shortcuts."; |
+ return base::FilePath(); |
+ } |
+ |
+ return folder; |
+} |
+ |
+const wchar_t kAllFiles[] = L"*"; |
+ |
+// Helper to perform common operations to shortcuts in a folder. |
+// Implement the ActOnShortcut() and ActOnFolder() to define operations. |
+class BatchShortcutOperation { |
gab
2013/04/24 21:41:46
I think it would be nicer, less verbose, and easie
huangs
2013/04/25 16:27:46
I think it's important to group it into a class, b
|
+ public: |
+ BatchShortcutOperation() {} |
+ virtual ~BatchShortcutOperation() {} |
+ |
+ // Goes through |shortcut_folder| and seeks shortcuts with names that match |
+ // |name_filter| (empty = none), and with targets given by |target_exe|. |
+ // Calls ActOnShortcut() with each matching shortcuts. Afterwards, calls |
+ // ActOnFolder() with |shortcut_folder|. |
+ // Returns true iff all operations are successful. |
+ bool Run(const base::FilePath& shortcut_folder, |
+ const string16& name_filter, |
+ const base::FilePath& target_exe); |
+ |
+ // Wrapper for Run(): first determine shortcut path based on given data. |
+ // |name| can specify the name for a single shortcut (without ".lnk" suffix), |
gab
2013/04/24 21:41:46
s/suffix/extension
gab
2013/04/24 21:41:46
I don't like relying on the extension being presen
huangs
2013/04/25 16:27:46
Done.
huangs
2013/04/25 16:27:46
Done; adding ".lnk" if missing (exception is empty
|
+ // or all shortcuts if NULL. |
+ bool RunForLocation(ShellUtil::ShortcutLocation location, |
+ BrowserDistribution* dist, |
+ const base::FilePath& target_exe, |
+ ShellUtil::ShellChange level, |
+ const string16* name); |
+ |
+ // Wrapper for Run(): specifying all shortcuts in the taskbar. |
+ bool RunForTaskbar(const base::FilePath& target_exe); |
+ |
+ // Returns: true on success. |
+ virtual bool ActOnShortcut(const base::FilePath& shortcut_path) const = 0; |
+ |
+ // Returns: true on success. |
+ virtual bool ActOnFolder(const base::FilePath& shortcut_folder) const = 0; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(BatchShortcutOperation); |
+}; |
+ |
+// |name_filter| will have ".lnk" appended. |
+bool BatchShortcutOperation::Run(const base::FilePath& shortcut_folder, |
+ const string16& name_filter, |
+ const base::FilePath& target_exe) { |
+ InstallUtil::ProgramCompare target_compare(target_exe); |
+ bool success = true; |
+ if (!name_filter.empty()) { |
+ string16 pattern = name_filter + installer::kLnkExt; |
+ file_util::FileEnumerator enumerator(shortcut_folder, false, |
+ file_util::FileEnumerator::FILES, pattern); |
+ for (base::FilePath shortcut_path = enumerator.Next(); |
+ !shortcut_path.empty(); |
+ shortcut_path = enumerator.Next()) { |
+ if (shortcut_path.Extension() == installer::kLnkExt) { |
gab
2013/04/24 21:41:46
You are already only enumerating files with the .l
huangs
2013/04/25 16:27:46
Changed to DCHECK_EQ().
|
+ base::FilePath target_path; |
+ if (base::win::ResolveShortcut(shortcut_path, &target_path, NULL)) { |
+ if (target_compare.EvaluatePath(target_path)) |
+ success = ActOnShortcut(shortcut_path) && success; |
+ } else { |
+ LOG(ERROR) << "Cannot resolve shortcut at " << shortcut_path.value(); |
+ success = false; |
+ } |
+ } |
+ } |
+ } |
+ success = ActOnFolder(shortcut_folder) && success; |
+ return success; |
+} |
+ |
+bool BatchShortcutOperation::RunForLocation( |
+ ShellUtil::ShortcutLocation location, |
+ BrowserDistribution* dist, |
+ const base::FilePath& target_exe, |
+ ShellUtil::ShellChange level, |
+ const string16* name) { |
gab
2013/04/24 21:41:46
If |name| is changed to a pattern (as suggested in
huangs
2013/04/25 16:27:46
I think I'll get rid of the ActOnFolder() stuff; w
|
+ base::FilePath shortcut_folder; |
+ if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder) || |
+ shortcut_folder.empty()) { |
+ NOTREACHED(); |
return false; |
+ } |
- if (InstallUtil::ProgramCompare(target_exe).EvaluatePath(target_path)) { |
- // Unpin the shortcut if it was ever pinned by the user or the installer. |
+ return Run(shortcut_folder, name ? *name : kAllFiles, target_exe); |
+} |
+ |
+bool BatchShortcutOperation::RunForTaskbar(const base::FilePath& target_exe) { |
+ base::FilePath taskbar_pins_path; |
+ if (!PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pins_path) || |
gab
2013/04/24 21:41:46
Feels like we should augment GetShortcutPath() ins
huangs
2013/04/25 16:27:46
Might be solved by removing ActOnFolder().
|
+ !file_util::PathExists(taskbar_pins_path)) { |
+ LOG(ERROR) << "Couldn't find path to taskbar pins."; |
+ return false; |
+ } |
+ |
+ return Run(taskbar_pins_path, kAllFiles, target_exe); |
gab
2013/04/24 21:41:46
Taskbar pins are special though, they have to be e
huangs
2013/04/25 16:27:46
Per earlier discussion, having a dedicated unpin o
|
+} |
+ |
+// Batch shortcut operation to unpin and/or delete shortcuts in a folder, |
+// and possibly remove the folder itself. |
+class BatchShortcutDelete: public BatchShortcutOperation { |
+ public: |
+ BatchShortcutDelete(bool unpin, bool delete_file, bool delete_folder); |
+ virtual ~BatchShortcutDelete() {} |
+ |
+ // Unpins and/or removes |shortcut_path|. |
+ // Returns true if deletion successful or if no deletion occurs. |
+ virtual bool ActOnShortcut(const base::FilePath& shortcut_path) const |
+ OVERRIDE; |
+ |
+ // Removes |shortcut_folder| if |delete_folder_|. |
+ // Returns true if deletion successful. |
+ virtual bool ActOnFolder(const base::FilePath& shortcut_folder) const |
+ OVERRIDE; |
+ |
+ private: |
+ bool unpin_; |
+ bool delete_file_; |
+ bool delete_folder_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BatchShortcutDelete); |
+}; |
+ |
+BatchShortcutDelete::BatchShortcutDelete(bool unpin, |
+ bool delete_file, |
+ bool delete_folder) |
gab
2013/04/24 21:41:46
(bool, bool, bool, bool, bool, bool, bool) interfa
huangs
2013/04/25 16:27:46
Adding accessors to explicitly set flags. But thi
|
+ : unpin_(unpin), |
+ delete_file_(delete_file), |
+ delete_folder_(delete_folder) { |
+} |
+ |
+bool BatchShortcutDelete::ActOnShortcut(const base::FilePath& shortcut_path) |
+ const { |
+ if (unpin_) { |
VLOG(1) << "Trying to unpin " << shortcut_path.value(); |
if (!base::win::TaskbarUnpinShortcutLink(shortcut_path.value().c_str())) { |
gab
2013/04/24 21:41:46
Did you check who uses RemoveShortcut(), is it sti
huangs
2013/04/25 16:27:46
There a routine that avoids calling this BECAUSE o
|
VLOG(1) << shortcut_path.value() |
<< " wasn't pinned (or the unpin failed)."; |
+ // Not an error condition, since shortcut might not be pinned. |
} |
- if (delete_folder) |
- return file_util::Delete(shortcut_path.DirName(), true); |
- else |
- return file_util::Delete(shortcut_path, false); |
} |
+ return delete_file_ ? file_util::Delete(shortcut_path, false) : true; |
+} |
+ |
+bool BatchShortcutDelete::ActOnFolder(const base::FilePath& shortcut_folder) |
+ const { |
+ return delete_folder_ ? file_util::Delete(shortcut_folder, true) : true; |
+} |
+ |
+// Batch shortcut operation to set target. |
+class BatchShortcutSetTarget: public BatchShortcutOperation { |
+ public: |
+ explicit BatchShortcutSetTarget(const base::FilePath& target); |
+ virtual ~BatchShortcutSetTarget() {} |
+ |
+ // Sets the target of |shortcut_path| to |target_|. |
+ // Returns true on success. |
+ virtual bool ActOnShortcut(const base::FilePath& shortcut_path) const |
+ OVERRIDE; |
+ |
+ // No-op; returns true. |
+ virtual bool ActOnFolder(const base::FilePath& shortcut_path) const OVERRIDE; |
+ |
+ private: |
+ base::FilePath target_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BatchShortcutSetTarget); |
+}; |
+ |
+BatchShortcutSetTarget::BatchShortcutSetTarget( |
+ const base::FilePath& target) |
+ : target_(target) { |
+} |
+ |
+bool BatchShortcutSetTarget::ActOnShortcut(const base::FilePath& shortcut_path) |
+ const { |
+ base::win::ShortcutProperties shortcut_properties; |
+ shortcut_properties.set_target(target_); |
+ shortcut_properties.set_working_dir(target_.DirName()); |
+ return base::win::CreateOrUpdateShortcutLink( |
+ shortcut_path, shortcut_properties, base::win::SHORTCUT_UPDATE_EXISTING); |
+} |
- // The shortcut at |shortcut_path| doesn't point to |target_exe|, act as if |
- // our shortcut had been deleted. |
+bool BatchShortcutSetTarget::ActOnFolder(const base::FilePath& shortcut_path) |
+ const { |
return true; |
} |
@@ -1858,103 +2038,85 @@ bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, |
} |
} |
+// static |
bool ShellUtil::RemoveShortcut(ShellUtil::ShortcutLocation location, |
BrowserDistribution* dist, |
const base::FilePath& target_exe, |
ShellChange level, |
const string16* shortcut_name) { |
- const bool delete_folder = (location == SHORTCUT_LOCATION_START_MENU); |
- |
- base::FilePath shortcut_folder; |
- if (!GetShortcutPath(location, dist, level, &shortcut_folder) || |
- shortcut_folder.empty()) { |
- NOTREACHED(); |
- return false; |
- } |
- |
- if (!delete_folder && !shortcut_name) { |
- file_util::FileEnumerator enumerator(shortcut_folder, false, |
- file_util::FileEnumerator::FILES); |
- bool had_failures = false; |
- for (base::FilePath path = enumerator.Next(); !path.empty(); |
- path = enumerator.Next()) { |
- if (path.Extension() != installer::kLnkExt) |
- continue; |
- |
- if (!MaybeRemoveShortcutAtPath(path, target_exe, delete_folder)) |
- had_failures = true; |
- } |
- return !had_failures; |
- } |
- |
- const string16 shortcut_base_name( |
- (shortcut_name ? *shortcut_name : dist->GetAppShortCutName()) + |
- installer::kLnkExt); |
- const base::FilePath shortcut_path( |
- shortcut_folder.Append(shortcut_base_name)); |
- if (!file_util::PathExists(shortcut_path)) |
- return true; |
- |
- return MaybeRemoveShortcutAtPath(shortcut_path, target_exe, delete_folder); |
+ bool delete_folder = (location == SHORTCUT_LOCATION_START_MENU); |
+ BatchShortcutDelete op(true, true, delete_folder); // Unpon and delete-file. |
gab
2013/04/24 21:41:46
nit: Unpon :)
huangs
2013/04/25 16:27:46
Done. :)
|
+ return op.RunForLocation(location, dist, target_exe, level, shortcut_name); |
} |
+// static |
void ShellUtil::RemoveTaskbarShortcuts(const string16& target_exe) { |
if (base::win::GetVersion() < base::win::VERSION_WIN7) |
return; |
- base::FilePath taskbar_pins_path; |
- if (!PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pins_path) || |
- !file_util::PathExists(taskbar_pins_path)) { |
- LOG(ERROR) << "Couldn't find path to taskbar pins."; |
- return; |
- } |
- |
- file_util::FileEnumerator shortcuts_enum( |
- taskbar_pins_path, false, |
- file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk")); |
- |
- base::FilePath target_path(target_exe); |
- InstallUtil::ProgramCompare target_compare(target_path); |
- for (base::FilePath shortcut_path = shortcuts_enum.Next(); |
- !shortcut_path.empty(); |
- shortcut_path = shortcuts_enum.Next()) { |
- base::FilePath read_target; |
- if (!base::win::ResolveShortcut(shortcut_path, &read_target, NULL)) { |
- LOG(ERROR) << "Couldn't resolve shortcut at " << shortcut_path.value(); |
- continue; |
- } |
- if (target_compare.EvaluatePath(read_target)) { |
- // Unpin this shortcut if it points to |target_exe|. |
- base::win::TaskbarUnpinShortcutLink(shortcut_path.value().c_str()); |
- } |
- } |
+ BatchShortcutDelete op(true, false, false); // Unpin only. |
+ op.RunForTaskbar(base::FilePath(target_exe)); |
} |
+// static |
void ShellUtil::RemoveStartScreenShortcuts(BrowserDistribution* dist, |
const string16& target_exe) { |
if (base::win::GetVersion() < base::win::VERSION_WIN8) |
return; |
- base::FilePath app_shortcuts_path; |
- if (!PathService::Get(base::DIR_APP_SHORTCUTS, &app_shortcuts_path)) { |
- LOG(ERROR) << "Could not get application shortcuts location to delete" |
- << " start screen shortcuts."; |
+ base::FilePath folder(GetAppShortcutsFolder(dist, target_exe)); |
gab
2013/04/24 21:41:46
This could probably also go in GetShortcutPath() a
huangs
2013/04/25 16:27:46
Will do this next. Can I remove / redo the messag
|
+ if (folder.empty()) |
return; |
+ |
+ BatchShortcutDelete op(false, false, true); // Delete-folder only. |
+ VLOG(1) << "Removing start screen shortcuts from " << folder.value(); |
+ if (!op.Run(folder, L"", base::FilePath())) { |
+ LOG(ERROR) << "Failed to remove start screen shortcuts from " |
+ << folder.value(); |
} |
+} |
+ |
+// static |
+bool ShellUtil::MigrateShortcut(ShellUtil::ShortcutLocation location, |
+ BrowserDistribution* dist, |
+ const base::FilePath& old_target_exe, |
+ const base::FilePath& new_target_exe, |
+ ShellChange level, |
+ const string16* shortcut_name) { |
+ bool delete_folder = (location == SHORTCUT_LOCATION_START_MENU); |
+ BatchShortcutSetTarget op(new_target_exe); |
+ return op.RunForLocation(location, dist, old_target_exe, level, |
+ shortcut_name); |
+} |
- app_shortcuts_path = app_shortcuts_path.Append( |
- GetBrowserModelId(dist, |
- InstallUtil::IsPerUserInstall(target_exe.c_str()))); |
- if (!file_util::DirectoryExists(app_shortcuts_path)) { |
- VLOG(1) << "No start screen shortcuts to delete."; |
+// static |
+void ShellUtil::MigrateTaskbarShortcuts(const string16& old_target_exe, |
+ const string16& new_target_exe) { |
+ if (base::win::GetVersion() < base::win::VERSION_WIN7) |
return; |
- } |
- VLOG(1) << "Removing start screen shortcuts from " |
- << app_shortcuts_path.value(); |
- if (!file_util::Delete(app_shortcuts_path, true)) { |
- LOG(ERROR) << "Failed to remove start screen shortcuts from " |
- << app_shortcuts_path.value(); |
+ base::FilePath new_target_path(new_target_exe); |
+ BatchShortcutSetTarget op(new_target_path); |
+ op.RunForTaskbar(base::FilePath(old_target_exe)); |
+} |
+ |
+// static |
+void ShellUtil::MigrateStartScreenShortcuts(BrowserDistribution* dist, |
+ const string16& old_target_exe, |
+ const string16& new_target_exe) { |
+ if (base::win::GetVersion() < base::win::VERSION_WIN8) |
+ return; |
+ |
+ base::FilePath folder(GetAppShortcutsFolder(dist, old_target_exe)); |
+ if (folder.empty()) |
+ return; |
+ |
+ base::FilePath new_target_path(new_target_exe); |
+ BatchShortcutSetTarget op(new_target_path); |
+ VLOG(1) << "Migrating start screen shortcuts from " << folder.value(); |
+ if (!op.Run(folder, kAllFiles, base::FilePath(old_target_exe))) { |
+ LOG(ERROR) << "Failed to migrate start screen shortcuts from " |
+ << folder.value(); |
} |
} |