Index: chrome/installer/util/shell_util.cc |
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc |
index 6cf76d989b02e71a5857e2512873b0cd7fbf29de..0a240044e06b7b563615c2acafc80a2cd14470f4 100644 |
--- a/chrome/installer/util/shell_util.cc |
+++ b/chrome/installer/util/shell_util.cc |
@@ -31,6 +31,7 @@ |
#include "base/utf_string_conversions.h" |
#include "base/values.h" |
#include "base/win/registry.h" |
+#include "base/win/scoped_co_mem.h" |
#include "base/win/scoped_comptr.h" |
#include "base/win/shortcut.h" |
#include "base/win/win_util.h" |
@@ -1015,6 +1016,157 @@ base::win::ShortcutProperties GetShortcutPropertiesFromChromeShortcutProperties( |
return shortcut_properties; |
} |
+// Gets the short (8.3) form of |path|, putting the result in |short_path| and |
+// returning true on success. |short_path| is not modified on failure. |
+bool ShortNameFromPath(const FilePath& path, string16* short_path) { |
+ DCHECK(short_path); |
+ string16 result(MAX_PATH, L'\0'); |
+ DWORD short_length = GetShortPathName(path.value().c_str(), &result[0], |
+ result.size()); |
+ if (short_length == 0 || short_length > result.size()) { |
+ PLOG(ERROR) << "Error getting short (8.3) path"; |
+ return false; |
+ } |
+ |
+ result.resize(short_length); |
+ short_path->swap(result); |
+ return true; |
+} |
+ |
+// Probe using IApplicationAssociationRegistration::QueryCurrentDefault |
+// (Windows 8); see ProbeProtocolHandlers. This mechanism is not suitable for |
+// use on previous versions of Windows despite the presence of |
+// QueryCurrentDefault on them since versions of Windows prior to Windows 8 |
+// did not perform validation on the ProgID registered as the current default. |
+// As a result, stale ProgIDs could be returned, leading to false positives. |
+ShellUtil::DefaultState ProbeCurrentDefaultHandlers( |
+ const wchar_t* const* protocols, |
+ size_t num_protocols) { |
+ base::win::ScopedComPtr<IApplicationAssociationRegistration> registration; |
+ HRESULT hr = registration.CreateInstance( |
+ CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC); |
+ if (FAILED(hr)) |
+ return ShellUtil::UNKNOWN_DEFAULT; |
+ |
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
+ FilePath chrome_exe; |
+ if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
+ NOTREACHED(); |
+ return ShellUtil::UNKNOWN_DEFAULT; |
+ } |
+ string16 prog_id(ShellUtil::kChromeHTMLProgId); |
+ prog_id += ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe.value()); |
+ |
+ for (size_t i = 0; i < num_protocols; ++i) { |
+ base::win::ScopedCoMem<wchar_t> current_app; |
+ hr = registration->QueryCurrentDefault(protocols[i], AT_URLPROTOCOL, |
+ AL_EFFECTIVE, ¤t_app); |
+ if (FAILED(hr) || prog_id.compare(current_app) != 0) |
+ return ShellUtil::NOT_DEFAULT; |
+ } |
+ |
+ return ShellUtil::IS_DEFAULT; |
+} |
+ |
+// Probe using IApplicationAssociationRegistration::QueryAppIsDefault (Vista and |
+// Windows 7); see ProbeProtocolHandlers. |
+ShellUtil::DefaultState ProbeAppIsDefaultHandlers( |
+ const wchar_t* const* protocols, |
+ size_t num_protocols) { |
+ base::win::ScopedComPtr<IApplicationAssociationRegistration> registration; |
+ HRESULT hr = registration.CreateInstance( |
+ CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC); |
+ if (FAILED(hr)) |
+ return ShellUtil::UNKNOWN_DEFAULT; |
+ |
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
+ FilePath chrome_exe; |
+ if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
+ NOTREACHED(); |
+ return ShellUtil::UNKNOWN_DEFAULT; |
+ } |
+ string16 app_name(ShellUtil::GetApplicationName(dist, chrome_exe.value())); |
+ |
+ BOOL result; |
+ for (size_t i = 0; i < num_protocols; ++i) { |
+ result = TRUE; |
+ hr = registration->QueryAppIsDefault(protocols[i], AT_URLPROTOCOL, |
+ AL_EFFECTIVE, app_name.c_str(), &result); |
+ if (FAILED(hr) || result == FALSE) |
+ return ShellUtil::NOT_DEFAULT; |
+ } |
+ |
+ return ShellUtil::IS_DEFAULT; |
+} |
+ |
+// Probe the current commands registered to handle the shell "open" verb for |
+// |protocols| (Windows XP); see ProbeProtocolHandlers. |
+ShellUtil::DefaultState ProbeOpenCommandHandlers( |
+ const wchar_t* const* protocols, |
+ size_t num_protocols) { |
+ // Get the path to the current exe (Chrome). |
+ FilePath app_path; |
+ if (!PathService::Get(base::FILE_EXE, &app_path)) { |
+ LOG(ERROR) << "Error getting app exe path"; |
+ return ShellUtil::UNKNOWN_DEFAULT; |
+ } |
+ |
+ // Get its short (8.3) form. |
+ string16 short_app_path; |
+ if (!ShortNameFromPath(app_path, &short_app_path)) |
+ return ShellUtil::UNKNOWN_DEFAULT; |
M-A Ruel
2015/10/14 20:08:04
This code is incorrect; it's possible that a path
gab
2015/10/14 20:32:07
This CL moved this code from shell_integration_win
Mark P
2015/10/14 22:07:19
Filed bug
https://code.google.com/p/chromium/issue
|
+ |
+ const HKEY root_key = HKEY_CLASSES_ROOT; |
+ string16 key_path; |
+ base::win::RegKey key; |
+ string16 value; |
+ CommandLine command_line(CommandLine::NO_PROGRAM); |
+ string16 short_path; |
+ |
+ for (size_t i = 0; i < num_protocols; ++i) { |
+ // Get the command line from HKCU\<protocol>\shell\open\command. |
+ key_path.assign(protocols[i]).append(ShellUtil::kRegShellOpen); |
+ if ((key.Open(root_key, key_path.c_str(), |
+ KEY_QUERY_VALUE) != ERROR_SUCCESS) || |
+ (key.ReadValue(L"", &value) != ERROR_SUCCESS)) { |
+ return ShellUtil::NOT_DEFAULT; |
+ } |
+ |
+ // Need to normalize path in case it's been munged. |
+ command_line = CommandLine::FromString(value); |
+ if (!ShortNameFromPath(command_line.GetProgram(), &short_path)) |
+ return ShellUtil::UNKNOWN_DEFAULT; |
+ |
+ if (!FilePath::CompareEqualIgnoreCase(short_path, short_app_path)) |
+ return ShellUtil::NOT_DEFAULT; |
+ } |
+ |
+ return ShellUtil::IS_DEFAULT; |
+} |
+ |
+// A helper function that probes default protocol handler registration (in a |
+// manner appropriate for the current version of Windows) to determine if |
+// Chrome is the default handler for |protocols|. Returns IS_DEFAULT_WEB_CLIENT |
+// only if Chrome is the default for all specified protocols. |
+ShellUtil::DefaultState ProbeProtocolHandlers( |
+ const wchar_t* const* protocols, |
+ size_t num_protocols) { |
+ DCHECK(!num_protocols || protocols); |
+ if (DCHECK_IS_ON()) { |
+ for (size_t i = 0; i < num_protocols; ++i) |
+ DCHECK(protocols[i] && *protocols[i]); |
+ } |
+ |
+ const base::win::Version windows_version = base::win::GetVersion(); |
+ |
+ if (windows_version >= base::win::VERSION_WIN8) |
+ return ProbeCurrentDefaultHandlers(protocols, num_protocols); |
+ else if (windows_version >= base::win::VERSION_VISTA) |
+ return ProbeAppIsDefaultHandlers(protocols, num_protocols); |
+ |
+ return ProbeOpenCommandHandlers(protocols, num_protocols); |
+} |
+ |
} // namespace |
const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon"; |
@@ -1336,6 +1488,29 @@ string16 ShellUtil::BuildAppModelId( |
return app_id; |
} |
+ShellUtil::DefaultState ShellUtil::IsChromeDefault() { |
+ // When we check for default browser we don't necessarily want to count file |
+ // type handlers and icons as having changed the default browser status, |
+ // since the user may have changed their shell settings to cause HTML files |
+ // to open with a text editor for example. We also don't want to aggressively |
+ // claim FTP, since the user may have a separate FTP client. It is an open |
+ // question as to how to "heal" these settings. Perhaps the user should just |
+ // re-run the installer or run with the --set-default-browser command line |
+ // flag. There is doubtless some other key we can hook into to cause "Repair" |
+ // to show up in Add/Remove programs for us. |
+ static const wchar_t* const kChromeProtocols[] = { L"http", L"https" }; |
+ return ProbeProtocolHandlers(kChromeProtocols, arraysize(kChromeProtocols)); |
+} |
+ |
+ShellUtil::DefaultState ShellUtil::IsChromeDefaultProtocolClient( |
+ const string16& protocol) { |
+ if (protocol.empty()) |
+ return UNKNOWN_DEFAULT; |
+ |
+ const wchar_t* const protocols[] = { protocol.c_str() }; |
+ return ProbeProtocolHandlers(protocols, arraysize(protocols)); |
+} |
+ |
// static |
bool ShellUtil::CanMakeChromeDefaultUnattended() { |
return base::win::GetVersion() < base::win::VERSION_WIN8; |