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

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

Issue 1896513002: Fix registerProtocolHandler implementation on Windows 8 and 10. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 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 side-by-side diff with in-line comments
Download patch
« chrome/installer/util/shell_util.h ('K') | « chrome/installer/util/shell_util.h ('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 202d8716381ad6b28dd97721e94f13e3d46e48ef..87346d024ac248d2ff947df805313f767143dbf5 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -80,6 +80,8 @@ enum RegistrationConfirmationLevel {
};
const wchar_t kReinstallCommand[] = L"ReinstallCommand";
+const wchar_t kSystemSettingsDefaultAppsFormat[] =
+ L"SystemSettings_DefaultApps_%ls";
// Returns the current (or installed) browser's ProgId (e.g.
// "ChromeHTML|suffix|").
@@ -709,24 +711,29 @@ bool ElevateAndRegisterChrome(BrowserDistribution* dist,
// Launches the Windows 'settings' modern app with the 'default apps' view
// focused. This only works for Windows 8 and Windows 10. The appModelId
-// looks arbitrary but it is the same in Win8 and Win10 previews. There
-// is no easy way to retrieve the appModelId from the registry.
-bool LaunchDefaultAppsSettingsModernDialog() {
+// looks arbitrary but it is the same in Win8 and Win10. There is no easy way to
+// retrieve the appModelId from the registry.
+bool LaunchDefaultAppsSettingsModernDialog(const wchar_t* target) {
grt (UTC plus 2) 2016/04/15 18:47:26 how about having this take the protocol rather tha
Patrick Monette 2016/04/15 21:35:42 Done.
+ DCHECK(target);
+ static const wchar_t kControlPanelAppModelId[] =
+ L"windows.immersivecontrolpanel_cw5n1h2txyewy"
+ L"!microsoft.windows.immersivecontrolpanel";
+
base::win::ScopedComPtr<IApplicationActivationManager> activator;
HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager);
if (SUCCEEDED(hr)) {
DWORD pid = 0;
CoAllowSetForegroundWindow(activator.get(), nullptr);
- hr = activator->ActivateApplication(
- L"windows.immersivecontrolpanel_cw5n1h2txyewy"
- L"!microsoft.windows.immersivecontrolpanel",
- L"page=SettingsPageAppsDefaults", AO_NONE, &pid);
+ hr = activator->ActivateApplication(kControlPanelAppModelId,
+ L"page=SettingsPageAppsDefaults",
+ AO_NONE, &pid);
if (SUCCEEDED(hr)) {
hr = activator->ActivateApplication(
- L"windows.immersivecontrolpanel_cw5n1h2txyewy"
- L"!microsoft.windows.immersivecontrolpanel",
- L"page=SettingsPageAppsDefaults"
- L"&target=SystemSettings_DefaultApps_Browser", AO_NONE, &pid);
+ kControlPanelAppModelId,
+ base::StringPrintf(L"page=SettingsPageAppsDefaults&target=%ls",
+ target)
+ .c_str(),
+ AO_NONE, &pid);
}
if (SUCCEEDED(hr))
return true;
@@ -1343,6 +1350,28 @@ bool RemoveShortcutFolderIfEmpty(ShellUtil::ShortcutLocation location,
return true;
}
+// Returns the target used as a activate parameter when opening the settings
+// pointing to the page that is the most relevant to a user trying to change the
+// default handler for |protocol|.
+base::string16 GetTargetForDefaultAppsSettings(const base::string16& protocol) {
+ if (protocol == L"mailto")
+ return base::StringPrintf(kSystemSettingsDefaultAppsFormat, L"Email");
+
+ return L"SettingsPageAppsDefaultsProtocolView";
+}
+
+// Creates the registry key <root hkey>\Software\Classes\<protocol>\URL Protocol
+// so that Windows allows the handler for this |protocol| to be be changed.
+bool CreateKeyForProtocol(const wchar_t* protocol) {
+ RegKey reg_key(HKEY_CURRENT_USER, ShellUtil::kRegClasses, KEY_ALL_ACCESS);
+ DCHECK(reg_key.Valid());
+ if (reg_key.CreateKey(protocol, KEY_CREATE_SUB_KEY | KEY_SET_VALUE) !=
+ ERROR_SUCCESS)
+ return false;
+
+ return reg_key.WriteValue(ShellUtil::kRegUrlProtocol, L"") == ERROR_SUCCESS;
+}
+
} // namespace
const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon";
@@ -1815,6 +1844,17 @@ bool ShellUtil::CanMakeChromeDefaultUnattended() {
return base::win::GetVersion() < base::win::VERSION_WIN8;
}
+// static
+ShellUtil::SetDefaultInteractiveMode ShellUtil::GetSetDefaultInteractiveMode() {
+ DCHECK(!CanMakeChromeDefaultUnattended());
+
+ if (base::win::GetVersion() == base::win::VERSION_WIN8) {
grt (UTC plus 2) 2016/04/15 18:47:26 nit: omit braces
Patrick Monette 2016/04/15 21:35:42 Done.
+ return SetDefaultInteractiveMode::INTENT_PICKER;
+ }
+
+ return SetDefaultInteractiveMode::SYSTEM_SETTINGS;
+}
+
bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
int shell_change,
const base::FilePath& chrome_exe,
@@ -1888,7 +1928,7 @@ bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
bool ShellUtil::ShowMakeChromeDefaultSystemUI(
BrowserDistribution* dist,
const base::FilePath& chrome_exe) {
- DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
+ DCHECK(!CanMakeChromeDefaultUnattended());
if (dist->GetDefaultBrowserControlPolicy() !=
BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
return false;
@@ -1900,22 +1940,27 @@ bool ShellUtil::ShowMakeChromeDefaultSystemUI(
bool succeeded = true;
bool is_default = (GetChromeDefaultState() == IS_DEFAULT);
if (!is_default) {
- if (base::win::GetVersion() < base::win::VERSION_WIN10) {
- // On Windows 8, you can't set yourself as the default handler
- // programatically. In other words IApplicationAssociationRegistration
- // has been rendered useless. What you can do is to launch
- // "Set Program Associations" section of the "Default Programs"
- // control panel, which is a mess, or pop the concise "How you want to
- // open webpages?" dialog. We choose the latter.
- ScopedUserProtocolEntry user_protocol_entry;
- succeeded = LaunchSelectDefaultProtocolHandlerDialog(L"http");
- } else {
- // On Windows 10, you can't even launch the associations dialog.
- // So we launch the settings dialog. Quoting from MSDN: "The Open With
- // dialog box can no longer be used to change the default program used to
- // open a file extension. You can only use SHOpenWithDialog to open
- // a single file."
- succeeded = LaunchDefaultAppsSettingsModernDialog();
+ switch (GetSetDefaultInteractiveMode()) {
+ case INTENT_PICKER: {
+ // On Windows 8, you can't set yourself as the default handler
+ // programatically. In other words IApplicationAssociationRegistration
+ // has been rendered useless. What you can do is to launch
+ // "Set Program Associations" section of the "Default Programs"
+ // control panel, which is a mess, or pop the concise "How you want to
+ // open webpages?" dialog. We choose the latter.
+ ScopedUserProtocolEntry user_protocol_entry;
+ succeeded = LaunchSelectDefaultProtocolHandlerDialog(L"http");
+ } break;
grt (UTC plus 2) 2016/04/15 18:47:26 is this what git cl format likes?
Patrick Monette 2016/04/15 21:35:42 Yes.
+ case SYSTEM_SETTINGS:
+ // On Windows 10, you can't even launch the associations dialog.
+ // So we launch the settings dialog. Quoting from MSDN: "The Open With
+ // dialog box can no longer be used to change the default program used
+ // to open a file extension. You can only use SHOpenWithDialog to open
+ // a single file."
+ succeeded = LaunchDefaultAppsSettingsModernDialog(
+ base::StringPrintf(kSystemSettingsDefaultAppsFormat, L"Browser")
grt (UTC plus 2) 2016/04/15 18:47:26 how about using GetTargetForDefaultAppsSettings(L"
Patrick Monette 2016/04/15 21:35:42 Done.
+ .c_str());
+ break;
}
is_default = (succeeded && GetChromeDefaultState() == IS_DEFAULT);
}
@@ -1977,7 +2022,7 @@ bool ShellUtil::ShowMakeChromeDefaultProtocolClientSystemUI(
BrowserDistribution* dist,
const base::FilePath& chrome_exe,
const base::string16& protocol) {
- DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
+ DCHECK(!CanMakeChromeDefaultUnattended());
if (dist->GetDefaultBrowserControlPolicy() !=
BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
return false;
@@ -1987,17 +2032,36 @@ bool ShellUtil::ShowMakeChromeDefaultProtocolClientSystemUI(
dist, chrome_exe, base::string16(), protocol, true))
return false;
+ // This registry key is required so Windows give the user the possibility to
+ // choose a default handler for |protocol|.
+ if (!CreateKeyForProtocol(protocol.c_str())) {
grt (UTC plus 2) 2016/04/15 18:47:26 is this doing the same thing that the ScopedUserPr
Patrick Monette 2016/04/15 21:35:42 Good point! I generalized it for all protocols so
+ DVLOG(1) << "Failed to create a valid key for the protocol " << protocol;
+ return false;
+ }
+
bool succeeded = true;
bool is_default = (
GetChromeDefaultProtocolClientState(protocol) == IS_DEFAULT);
if (!is_default) {
- // On Windows 8, you can't set yourself as the default handler
- // programatically. In other words IApplicationAssociationRegistration
- // has been rendered useless. What you can do is to launch
- // "Set Program Associations" section of the "Default Programs"
- // control panel, which is a mess, or pop the concise "How you want to open
- // links of this type (protocol)?" dialog. We choose the latter.
- succeeded = LaunchSelectDefaultProtocolHandlerDialog(protocol.c_str());
+ switch (GetSetDefaultInteractiveMode()) {
+ case INTENT_PICKER: {
+ // On Windows 8, you can't set yourself as the default handler
+ // programatically. In other words IApplicationAssociationRegistration
+ // has been rendered useless. What you can do is to launch
+ // "Set Program Associations" section of the "Default Programs"
+ // control panel, which is a mess, or pop the concise "How you want to
+ // open
+ // links of this type (protocol)?" dialog. We choose the latter.
+ ScopedUserProtocolEntry user_protocol_entry;
grt (UTC plus 2) 2016/04/15 18:47:26 as-is, this is specifically for http, so it isn't
Patrick Monette 2016/04/15 21:35:41 Done.
+ succeeded = LaunchSelectDefaultProtocolHandlerDialog(protocol.c_str());
+ } break;
+ case SYSTEM_SETTINGS:
+ // On Windows 10, you can't even launch the associations dialog.
+ // So we launch the settings dialog.
+ succeeded = LaunchDefaultAppsSettingsModernDialog(
+ GetTargetForDefaultAppsSettings(protocol).c_str());
+ break;
+ }
is_default = (succeeded &&
GetChromeDefaultProtocolClientState(protocol) == IS_DEFAULT);
}
« chrome/installer/util/shell_util.h ('K') | « chrome/installer/util/shell_util.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698