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

Unified Diff: chrome/installer/util/shell_util.cc

Issue 1294863006: Do not register Chrome's DelegateExecute on Win10+. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@d1_fix_debug_versioninfo
Patch Set: tweak IsChromeRegistered to support RemovalFlag Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/installer/setup/install_worker.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/installer/util/shell_util.cc
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 46defa119135f89d76b0d7b2578fecf14bdeea31..2b8ed146342745ea78e8282238bdf6625d929f0c 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -77,29 +77,12 @@ enum RegistrationConfirmationLevel {
const wchar_t kReinstallCommand[] = L"ReinstallCommand";
-// Returns true if Chrome Metro is supported on this OS (Win 8 8370 or greater).
-// TODO(gab): Change this to a simple check for Win 8 once old Win8 builds
-// become irrelevant.
+// Returns true if Chrome Metro is supported on this version of Windows
+// (supported as of Win8; deprecated as of Win10).
bool IsChromeMetroSupported() {
- OSVERSIONINFOEX min_version_info = {};
- min_version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- min_version_info.dwMajorVersion = 6;
- min_version_info.dwMinorVersion = 2;
- min_version_info.dwBuildNumber = 8370;
- min_version_info.wServicePackMajor = 0;
- min_version_info.wServicePackMinor = 0;
-
- DWORDLONG condition_mask = 0;
- VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
- VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_GREATER_EQUAL);
- VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
- VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
- VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
-
- DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER |
- VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
-
- return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0;
+ const base::win::Version win_version = base::win::GetVersion();
+ return win_version >= base::win::VERSION_WIN8 &&
+ win_version < base::win::VERSION_WIN10;
}
// Returns the current (or installed) browser's ProgId (e.g.
@@ -192,6 +175,16 @@ class RegistryEntry {
LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM,
};
+ // Identifies the type of removal this RegistryEntry is flagged for, if any.
+ enum class RemovalFlag {
+ // Default case: install the key/value.
+ NONE,
+ // Registry value under |key_path_|\|name_| is flagged for deletion.
+ VALUE,
+ // Registry key under |key_path_| is flag for deletion.
+ KEY,
+ };
+
// Details about a Windows application, to be entered into the registry for
// the purpose of file associations.
struct ApplicationInfo {
@@ -251,6 +244,68 @@ class RegistryEntry {
return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities");
}
+ // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is
+ // only needed for registring a web browser, not for general associations.
+ static ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries(
+ const base::FilePath& chrome_exe,
+ const ApplicationInfo& app_info) {
+ ScopedVector<RegistryEntry> entries;
+
+ base::string16 app_id_shell_key(ShellUtil::kRegClasses);
+ app_id_shell_key.push_back(base::FilePath::kSeparators[0]);
+ app_id_shell_key.append(app_info.app_id);
+ app_id_shell_key.append(ShellUtil::kRegExePath);
+ app_id_shell_key.append(ShellUtil::kRegShellPath);
+
+ // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
+ entries.push_back(
+ new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen));
+
+ // The command to execute when opening this application via the Metro UI.
+ const base::string16 delegate_command(
+ ShellUtil::GetChromeDelegateCommand(chrome_exe));
+
+ // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is
+ // registered to handle some verbs. This registration has the side-effect
+ // that these verbs now show up in the shortcut's context menu. We
+ // mitigate this side-effect by making the context menu entries
+ // user readable/localized strings. See relevant MSDN article:
+ // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
+ static const struct {
+ const wchar_t* verb;
+ int name_id;
+ } verbs[] = {
+ {ShellUtil::kRegVerbOpen, -1},
+ {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE},
+ };
+ for (const auto& verb_and_id : verbs) {
+ base::string16 sub_path(app_id_shell_key);
+ sub_path.push_back(base::FilePath::kSeparators[0]);
+ sub_path.append(verb_and_id.verb);
+
+ // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
+ if (verb_and_id.name_id != -1) {
+ // TODO(grt): http://crbug.com/75152 Write a reference to a localized
+ // resource.
+ const base::string16 verb_name(
+ installer::GetLocalizedString(verb_and_id.name_id));
+ entries.push_back(new RegistryEntry(sub_path, verb_name.c_str()));
+ }
+ entries.push_back(
+ new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch"));
+
+ sub_path.push_back(base::FilePath::kSeparators[0]);
+ sub_path.append(ShellUtil::kRegCommand);
+
+ // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
+ entries.push_back(new RegistryEntry(sub_path, delegate_command));
+ entries.push_back(new RegistryEntry(
+ sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
+ }
+
+ return entries.Pass();
+ }
+
// This method returns a list of all the registry entries that
// are needed to register this installation's ProgId and AppId.
// These entries need to be registered in HKLM prior to Win8.
@@ -273,13 +328,6 @@ class RegistryEntry {
app_info.app_id = ShellUtil::GetBrowserModelId(
dist, InstallUtil::IsPerUserInstall(chrome_exe));
- // The command to execute when opening this application via the Metro UI.
- base::string16 delegate_command(
- ShellUtil::GetChromeDelegateCommand(chrome_exe));
- bool set_delegate_execute =
- IsChromeMetroSupported() &&
- dist->GetCommandExecuteImplClsid(&app_info.delegate_clsid);
-
// TODO(grt): http://crbug.com/75152 Write a reference to a localized
// resource for name, description, and company.
app_info.application_name = dist->GetDisplayName();
@@ -288,58 +336,23 @@ class RegistryEntry {
app_info.application_description = dist->GetAppDescription();
app_info.publisher_name = dist->GetPublisherName();
- GetProgIdEntries(app_info, entries);
-
- // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is
- // only needed for registring a web browser, not for general associations.
- if (set_delegate_execute) {
- base::string16 model_id_shell(ShellUtil::kRegClasses);
- model_id_shell.push_back(base::FilePath::kSeparators[0]);
- model_id_shell.append(app_info.app_id);
- model_id_shell.append(ShellUtil::kRegExePath);
- model_id_shell.append(ShellUtil::kRegShellPath);
-
- // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
- entries->push_back(new RegistryEntry(model_id_shell,
- ShellUtil::kRegVerbOpen));
-
- // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is
- // registered to handle some verbs. This registration has the side-effect
- // that these verbs now show up in the shortcut's context menu. We
- // mitigate this side-effect by making the context menu entries
- // user readable/localized strings. See relevant MSDN article:
- // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
- const struct {
- const wchar_t* verb;
- int name_id;
- } verbs[] = {
- { ShellUtil::kRegVerbOpen, -1 },
- { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE },
- };
- for (size_t i = 0; i < arraysize(verbs); ++i) {
- base::string16 sub_path(model_id_shell);
- sub_path.push_back(base::FilePath::kSeparators[0]);
- sub_path.append(verbs[i].verb);
-
- // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
- if (verbs[i].name_id != -1) {
- // TODO(grt): http://crbug.com/75152 Write a reference to a localized
- // resource.
- base::string16 verb_name(
- installer::GetLocalizedString(verbs[i].name_id));
- entries->push_back(new RegistryEntry(sub_path, verb_name.c_str()));
- }
- entries->push_back(new RegistryEntry(
- sub_path, L"CommandId", L"Browser.Launch"));
+ dist->GetCommandExecuteImplClsid(&app_info.delegate_clsid);
- sub_path.push_back(base::FilePath::kSeparators[0]);
- sub_path.append(ShellUtil::kRegCommand);
+ GetProgIdEntries(app_info, entries);
- // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
- entries->push_back(new RegistryEntry(sub_path, delegate_command));
- entries->push_back(new RegistryEntry(
- sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
+ if (!app_info.delegate_clsid.empty()) {
+ ScopedVector<RegistryEntry> delegate_execute_entries =
+ GetChromeDelegateExecuteEntries(chrome_exe, app_info);
+ if (!IsChromeMetroSupported()) {
+ // Remove the keys (not only their values) so that Windows will continue
+ // to launch Chrome without a pesky association error.
+ for (RegistryEntry* entry : delegate_execute_entries)
+ entry->set_removal_flag(RemovalFlag::KEY);
}
+ // Move |delegate_execute_entries| to |entries|.
+ entries->insert(entries->end(), delegate_execute_entries.begin(),
+ delegate_execute_entries.end());
+ delegate_execute_entries.weak_clear();
}
}
@@ -368,6 +381,10 @@ class RegistryEntry {
new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen,
ShellUtil::kRegDelegateExecute,
app_info.delegate_clsid));
+ // If Metro is not supported, remove the DelegateExecute entry instead of
+ // adding it.
+ if (!IsChromeMetroSupported())
+ entries->back()->set_removal_flag(RemovalFlag::VALUE);
}
// The following entries are required as of Windows 8, but do not
@@ -646,19 +663,43 @@ class RegistryEntry {
entries->push_back(new RegistryEntry(start_menu, app_name));
}
- // Generate work_item tasks required to create current registry entry and
- // add them to the given work item list.
+ // Flags this RegistryKey with |removal_flag|, indicating that it should be
+ // removed rather than created. Note that this will not result in cleaning up
+ // the entire registry hierarchy below RegistryEntry even if it is left empty
+ // by this operation (this should thus not be used for uninstall, but only to
+ // unregister keys that should explicitly no longer be active in the current
+ // configuration).
+ void set_removal_flag(RemovalFlag removal_flag) {
+ removal_flag_ = removal_flag;
+ }
+
+ // Generates work_item tasks required to create (or potentially delete based
+ // on |removal_flag_|) the current RegistryEntry and add them to the given
+ // work item list.
void AddToWorkItemList(HKEY root, WorkItemList *items) const {
- items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
- if (is_string_) {
- items->AddSetRegValueWorkItem(
- root, key_path_, WorkItem::kWow64Default, name_, value_, true);
+ if (removal_flag_ == RemovalFlag::VALUE) {
+ items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
+ name_);
+ } else if (removal_flag_ == RemovalFlag::KEY) {
+ items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
} else {
- items->AddSetRegValueWorkItem(
- root, key_path_, WorkItem::kWow64Default, name_, int_value_, true);
+ DCHECK(removal_flag_ == RemovalFlag::NONE);
+ items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
+ if (is_string_) {
+ items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
+ name_, value_, true);
+ } else {
+ items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
+ name_, int_value_, true);
+ }
}
}
+ // Returns true if this key is flagged for removal.
+ bool IsFlaggedForRemoval() const {
+ return removal_flag_ != RemovalFlag::NONE;
+ }
+
// Checks if the current registry entry exists in HKCU\|key_path_|\|name_|
// and value is |value_|. If the key does NOT exist in HKCU, checks for
// the correct name and value in HKLM.
@@ -710,23 +751,34 @@ class RegistryEntry {
// Create a object that represent default value of a key
RegistryEntry(const base::string16& key_path, const base::string16& value)
- : key_path_(key_path), name_(),
- is_string_(true), value_(value), int_value_(0) {
- }
+ : key_path_(key_path),
+ name_(),
+ is_string_(true),
+ value_(value),
+ int_value_(0),
+ removal_flag_(RemovalFlag::NONE) {}
// Create a object that represent a key of type REG_SZ
- RegistryEntry(const base::string16& key_path, const base::string16& name,
+ RegistryEntry(const base::string16& key_path,
+ const base::string16& name,
const base::string16& value)
- : key_path_(key_path), name_(name),
- is_string_(true), value_(value), int_value_(0) {
- }
+ : key_path_(key_path),
+ name_(name),
+ is_string_(true),
+ value_(value),
+ int_value_(0),
+ removal_flag_(RemovalFlag::NONE) {}
// Create a object that represent a key of integer type
- RegistryEntry(const base::string16& key_path, const base::string16& name,
+ RegistryEntry(const base::string16& key_path,
+ const base::string16& name,
DWORD value)
- : key_path_(key_path), name_(name),
- is_string_(false), value_(), int_value_(value) {
- }
+ : key_path_(key_path),
+ name_(name),
+ is_string_(false),
+ value_(),
+ int_value_(value),
+ removal_flag_(RemovalFlag::NONE) {}
base::string16 key_path_; // key path for the registry entry
base::string16 name_; // name of the registry entry
@@ -734,6 +786,10 @@ class RegistryEntry {
base::string16 value_; // string value (useful if is_string_ = true)
DWORD int_value_; // integer value (useful if is_string_ = false)
+ // Identifies whether this RegistryEntry is flagged for removal (i.e. no
+ // longer relevant on the configuration it was created under).
+ RemovalFlag removal_flag_;
+
// Helper function for ExistsInRegistry().
// Returns the RegistryStatus of the current registry entry in
// |root|\|key_path_|\|name_|.
@@ -784,24 +840,21 @@ bool AddRegistryEntries(HKEY root, const ScopedVector<RegistryEntry>& entries) {
return true;
}
-// Checks that all |entries| are present on this computer.
-// |look_for_in| is passed to RegistryEntry::ExistsInRegistry(). Documentation
-// for it can be found there.
-bool AreEntriesRegistered(const ScopedVector<RegistryEntry>& entries,
+// Checks that all |entries| are present on this computer (or absent if their
+// |removal_flag_| is set). |look_for_in| is passed to
+// RegistryEntry::ExistsInRegistry(). Documentation for it can be found there.
+bool AreEntriesAsDesired(const ScopedVector<RegistryEntry>& entries,
uint32 look_for_in) {
- bool registered = true;
- for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin();
- registered && itr != entries.end(); ++itr) {
- // We do not need registered = registered && ... since the loop condition
- // is set to exit early.
- registered = (*itr)->ExistsInRegistry(look_for_in);
+ for (const auto* entry : entries) {
+ if (entry->ExistsInRegistry(look_for_in) != !entry->IsFlaggedForRemoval())
+ return false;
}
- return registered;
+ return true;
}
-// Checks that all required registry entries for Chrome are already present
-// on this computer. See RegistryEntry::ExistsInRegistry for the behavior of
-// |look_for_in|.
+// Checks that all required registry entries for Chrome are already present on
+// this computer (or absent if their |removal_flag_| is set).
+// See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|.
// Note: between r133333 and r154145 we were registering parts of Chrome in HKCU
// and parts in HKLM for user-level installs; we now always register everything
// under a single registry root. Not doing so caused http://crbug.com/144910 for
@@ -817,7 +870,7 @@ bool IsChromeRegistered(BrowserDistribution* dist,
RegistryEntry::GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries);
RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries);
RegistryEntry::GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries);
- return AreEntriesRegistered(entries, look_for_in);
+ return AreEntriesAsDesired(entries, look_for_in);
}
// This method checks if Chrome is already registered on the local machine
@@ -829,7 +882,7 @@ bool IsChromeRegisteredForProtocol(BrowserDistribution* dist,
uint32 look_for_in) {
ScopedVector<RegistryEntry> entries;
RegistryEntry::GetProtocolCapabilityEntries(dist, suffix, protocol, &entries);
- return AreEntriesRegistered(entries, look_for_in);
+ return AreEntriesAsDesired(entries, look_for_in);
}
// This method registers Chrome on Vista by launching an elevated setup.exe.
@@ -1155,7 +1208,7 @@ base::win::ShortcutProperties TranslateShortcutProperties(
// <root>\Software\Classes\Chrome<.suffix>\.exe\shell\run on Windows 8.
void RemoveRunVerbOnWindows8(BrowserDistribution* dist,
const base::FilePath& chrome_exe) {
- if (IsChromeMetroSupported()) {
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
bool is_per_user_install = InstallUtil::IsPerUserInstall(chrome_exe);
HKEY root_key = DetermineRegistrationRoot(is_per_user_install);
// There's no need to rollback, so forgo the usual work item lists and just
@@ -2258,7 +2311,7 @@ bool ShellUtil::RegisterChromeBrowser(BrowserDistribution* dist,
// with no suffix (as per the old registration style): in which case some
// other registry entries could refer to them and since we were not able to
// set our HKLM entries above, we are better off not altering these here.
- if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) {
+ if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) {
if (!suffix.empty()) {
entries.clear();
RegistryEntry::GetChromeProgIdEntries(
« no previous file with comments | « chrome/installer/setup/install_worker.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698