Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 // This file defines functions that integrate Chrome in Windows shell. These | 5 // This file defines functions that integrate Chrome in Windows shell. These |
| 6 // functions can be used by Chrome as well as Chrome installer. All of the | 6 // functions can be used by Chrome as well as Chrome installer. All of the |
| 7 // work is done by the local functions defined in anonymous namespace in | 7 // work is done by the local functions defined in anonymous namespace in |
| 8 // this class. | 8 // this class. |
| 9 | 9 |
| 10 #include "chrome/installer/util/shell_util.h" | 10 #include "chrome/installer/util/shell_util.h" |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/scoped_ptr.h" |
| 25 #include "base/memory/scoped_vector.h" | 25 #include "base/memory/scoped_vector.h" |
| 26 #include "base/path_service.h" | 26 #include "base/path_service.h" |
| 27 #include "base/string16.h" | 27 #include "base/string16.h" |
| 28 #include "base/string_number_conversions.h" | 28 #include "base/string_number_conversions.h" |
| 29 #include "base/string_split.h" | 29 #include "base/string_split.h" |
| 30 #include "base/string_util.h" | 30 #include "base/string_util.h" |
| 31 #include "base/utf_string_conversions.h" | 31 #include "base/utf_string_conversions.h" |
| 32 #include "base/values.h" | 32 #include "base/values.h" |
| 33 #include "base/win/registry.h" | 33 #include "base/win/registry.h" |
| 34 #include "base/win/scoped_co_mem.h" | |
| 34 #include "base/win/scoped_comptr.h" | 35 #include "base/win/scoped_comptr.h" |
| 35 #include "base/win/shortcut.h" | 36 #include "base/win/shortcut.h" |
| 36 #include "base/win/win_util.h" | 37 #include "base/win/win_util.h" |
| 37 #include "base/win/windows_version.h" | 38 #include "base/win/windows_version.h" |
| 38 #include "chrome/common/chrome_constants.h" | 39 #include "chrome/common/chrome_constants.h" |
| 39 #include "chrome/common/chrome_switches.h" | 40 #include "chrome/common/chrome_switches.h" |
| 40 #include "chrome/installer/util/browser_distribution.h" | 41 #include "chrome/installer/util/browser_distribution.h" |
| 41 #include "chrome/installer/util/install_util.h" | 42 #include "chrome/installer/util/install_util.h" |
| 42 #include "chrome/installer/util/master_preferences.h" | 43 #include "chrome/installer/util/master_preferences.h" |
| 43 #include "chrome/installer/util/master_preferences_constants.h" | 44 #include "chrome/installer/util/master_preferences_constants.h" |
| (...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1008 shortcut_properties.set_app_id( | 1009 shortcut_properties.set_app_id( |
| 1009 ShellUtil::GetBrowserModelId(dist, is_per_user_install)); | 1010 ShellUtil::GetBrowserModelId(dist, is_per_user_install)); |
| 1010 } | 1011 } |
| 1011 | 1012 |
| 1012 if (properties.has_dual_mode()) | 1013 if (properties.has_dual_mode()) |
| 1013 shortcut_properties.set_dual_mode(properties.dual_mode); | 1014 shortcut_properties.set_dual_mode(properties.dual_mode); |
| 1014 | 1015 |
| 1015 return shortcut_properties; | 1016 return shortcut_properties; |
| 1016 } | 1017 } |
| 1017 | 1018 |
| 1019 // Gets the short (8.3) form of |path|, putting the result in |short_path| and | |
| 1020 // returning true on success. |short_path| is not modified on failure. | |
| 1021 bool ShortNameFromPath(const FilePath& path, string16* short_path) { | |
| 1022 DCHECK(short_path); | |
| 1023 string16 result(MAX_PATH, L'\0'); | |
| 1024 DWORD short_length = GetShortPathName(path.value().c_str(), &result[0], | |
| 1025 result.size()); | |
| 1026 if (short_length == 0 || short_length > result.size()) { | |
| 1027 PLOG(ERROR) << "Error getting short (8.3) path"; | |
| 1028 return false; | |
| 1029 } | |
| 1030 | |
| 1031 result.resize(short_length); | |
| 1032 short_path->swap(result); | |
| 1033 return true; | |
| 1034 } | |
| 1035 | |
| 1036 // Probe using IApplicationAssociationRegistration::QueryCurrentDefault | |
| 1037 // (Windows 8); see ProbeProtocolHandlers. This mechanism is not suitable for | |
| 1038 // use on previous versions of Windows despite the presence of | |
| 1039 // QueryCurrentDefault on them since versions of Windows prior to Windows 8 | |
| 1040 // did not perform validation on the ProgID registered as the current default. | |
| 1041 // As a result, stale ProgIDs could be returned, leading to false positives. | |
| 1042 ShellUtil::DefaultState ProbeCurrentDefaultHandlers( | |
| 1043 const wchar_t* const* protocols, | |
| 1044 size_t num_protocols) { | |
| 1045 base::win::ScopedComPtr<IApplicationAssociationRegistration> registration; | |
| 1046 HRESULT hr = registration.CreateInstance( | |
| 1047 CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC); | |
| 1048 if (FAILED(hr)) | |
| 1049 return ShellUtil::UNKNOWN_DEFAULT; | |
| 1050 | |
| 1051 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 1052 FilePath chrome_exe; | |
| 1053 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | |
| 1054 NOTREACHED(); | |
| 1055 return ShellUtil::UNKNOWN_DEFAULT; | |
| 1056 } | |
| 1057 string16 prog_id(ShellUtil::kChromeHTMLProgId); | |
| 1058 prog_id += ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe.value()); | |
| 1059 | |
| 1060 for (size_t i = 0; i < num_protocols; ++i) { | |
| 1061 base::win::ScopedCoMem<wchar_t> current_app; | |
| 1062 hr = registration->QueryCurrentDefault(protocols[i], AT_URLPROTOCOL, | |
| 1063 AL_EFFECTIVE, ¤t_app); | |
| 1064 if (FAILED(hr) || prog_id.compare(current_app) != 0) | |
| 1065 return ShellUtil::NOT_DEFAULT; | |
| 1066 } | |
| 1067 | |
| 1068 return ShellUtil::IS_DEFAULT; | |
| 1069 } | |
| 1070 | |
| 1071 // Probe using IApplicationAssociationRegistration::QueryAppIsDefault (Vista and | |
| 1072 // Windows 7); see ProbeProtocolHandlers. | |
| 1073 ShellUtil::DefaultState ProbeAppIsDefaultHandlers( | |
| 1074 const wchar_t* const* protocols, | |
| 1075 size_t num_protocols) { | |
| 1076 base::win::ScopedComPtr<IApplicationAssociationRegistration> registration; | |
| 1077 HRESULT hr = registration.CreateInstance( | |
| 1078 CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC); | |
| 1079 if (FAILED(hr)) | |
| 1080 return ShellUtil::UNKNOWN_DEFAULT; | |
| 1081 | |
| 1082 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 1083 FilePath chrome_exe; | |
| 1084 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | |
| 1085 NOTREACHED(); | |
| 1086 return ShellUtil::UNKNOWN_DEFAULT; | |
| 1087 } | |
| 1088 string16 app_name(ShellUtil::GetApplicationName(dist, chrome_exe.value())); | |
| 1089 | |
| 1090 BOOL result; | |
| 1091 for (size_t i = 0; i < num_protocols; ++i) { | |
| 1092 result = TRUE; | |
| 1093 hr = registration->QueryAppIsDefault(protocols[i], AT_URLPROTOCOL, | |
| 1094 AL_EFFECTIVE, app_name.c_str(), &result); | |
| 1095 if (FAILED(hr) || result == FALSE) | |
| 1096 return ShellUtil::NOT_DEFAULT; | |
| 1097 } | |
| 1098 | |
| 1099 return ShellUtil::IS_DEFAULT; | |
| 1100 } | |
| 1101 | |
| 1102 // Probe the current commands registered to handle the shell "open" verb for | |
| 1103 // |protocols| (Windows XP); see ProbeProtocolHandlers. | |
| 1104 ShellUtil::DefaultState ProbeOpenCommandHandlers( | |
| 1105 const wchar_t* const* protocols, | |
| 1106 size_t num_protocols) { | |
| 1107 // Get the path to the current exe (Chrome). | |
| 1108 FilePath app_path; | |
| 1109 if (!PathService::Get(base::FILE_EXE, &app_path)) { | |
| 1110 LOG(ERROR) << "Error getting app exe path"; | |
| 1111 return ShellUtil::UNKNOWN_DEFAULT; | |
| 1112 } | |
| 1113 | |
| 1114 // Get its short (8.3) form. | |
| 1115 string16 short_app_path; | |
| 1116 if (!ShortNameFromPath(app_path, &short_app_path)) | |
| 1117 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
| |
| 1118 | |
| 1119 const HKEY root_key = HKEY_CLASSES_ROOT; | |
| 1120 string16 key_path; | |
| 1121 base::win::RegKey key; | |
| 1122 string16 value; | |
| 1123 CommandLine command_line(CommandLine::NO_PROGRAM); | |
| 1124 string16 short_path; | |
| 1125 | |
| 1126 for (size_t i = 0; i < num_protocols; ++i) { | |
| 1127 // Get the command line from HKCU\<protocol>\shell\open\command. | |
| 1128 key_path.assign(protocols[i]).append(ShellUtil::kRegShellOpen); | |
| 1129 if ((key.Open(root_key, key_path.c_str(), | |
| 1130 KEY_QUERY_VALUE) != ERROR_SUCCESS) || | |
| 1131 (key.ReadValue(L"", &value) != ERROR_SUCCESS)) { | |
| 1132 return ShellUtil::NOT_DEFAULT; | |
| 1133 } | |
| 1134 | |
| 1135 // Need to normalize path in case it's been munged. | |
| 1136 command_line = CommandLine::FromString(value); | |
| 1137 if (!ShortNameFromPath(command_line.GetProgram(), &short_path)) | |
| 1138 return ShellUtil::UNKNOWN_DEFAULT; | |
| 1139 | |
| 1140 if (!FilePath::CompareEqualIgnoreCase(short_path, short_app_path)) | |
| 1141 return ShellUtil::NOT_DEFAULT; | |
| 1142 } | |
| 1143 | |
| 1144 return ShellUtil::IS_DEFAULT; | |
| 1145 } | |
| 1146 | |
| 1147 // A helper function that probes default protocol handler registration (in a | |
| 1148 // manner appropriate for the current version of Windows) to determine if | |
| 1149 // Chrome is the default handler for |protocols|. Returns IS_DEFAULT_WEB_CLIENT | |
| 1150 // only if Chrome is the default for all specified protocols. | |
| 1151 ShellUtil::DefaultState ProbeProtocolHandlers( | |
| 1152 const wchar_t* const* protocols, | |
| 1153 size_t num_protocols) { | |
| 1154 DCHECK(!num_protocols || protocols); | |
| 1155 if (DCHECK_IS_ON()) { | |
| 1156 for (size_t i = 0; i < num_protocols; ++i) | |
| 1157 DCHECK(protocols[i] && *protocols[i]); | |
| 1158 } | |
| 1159 | |
| 1160 const base::win::Version windows_version = base::win::GetVersion(); | |
| 1161 | |
| 1162 if (windows_version >= base::win::VERSION_WIN8) | |
| 1163 return ProbeCurrentDefaultHandlers(protocols, num_protocols); | |
| 1164 else if (windows_version >= base::win::VERSION_VISTA) | |
| 1165 return ProbeAppIsDefaultHandlers(protocols, num_protocols); | |
| 1166 | |
| 1167 return ProbeOpenCommandHandlers(protocols, num_protocols); | |
| 1168 } | |
| 1169 | |
| 1018 } // namespace | 1170 } // namespace |
| 1019 | 1171 |
| 1020 const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon"; | 1172 const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon"; |
| 1021 const wchar_t* ShellUtil::kRegShellPath = L"\\shell"; | 1173 const wchar_t* ShellUtil::kRegShellPath = L"\\shell"; |
| 1022 const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command"; | 1174 const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command"; |
| 1023 const wchar_t* ShellUtil::kRegStartMenuInternet = | 1175 const wchar_t* ShellUtil::kRegStartMenuInternet = |
| 1024 L"Software\\Clients\\StartMenuInternet"; | 1176 L"Software\\Clients\\StartMenuInternet"; |
| 1025 const wchar_t* ShellUtil::kRegClasses = L"Software\\Classes"; | 1177 const wchar_t* ShellUtil::kRegClasses = L"Software\\Classes"; |
| 1026 const wchar_t* ShellUtil::kRegRegisteredApplications = | 1178 const wchar_t* ShellUtil::kRegRegisteredApplications = |
| 1027 L"Software\\RegisteredApplications"; | 1179 L"Software\\RegisteredApplications"; |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1329 string16::npos); | 1481 string16::npos); |
| 1330 } else { | 1482 } else { |
| 1331 app_id.append(component); | 1483 app_id.append(component); |
| 1332 } | 1484 } |
| 1333 } | 1485 } |
| 1334 // No spaces are allowed in the AppUserModelId according to MSDN. | 1486 // No spaces are allowed in the AppUserModelId according to MSDN. |
| 1335 ReplaceChars(app_id, L" ", L"_", &app_id); | 1487 ReplaceChars(app_id, L" ", L"_", &app_id); |
| 1336 return app_id; | 1488 return app_id; |
| 1337 } | 1489 } |
| 1338 | 1490 |
| 1491 ShellUtil::DefaultState ShellUtil::IsChromeDefault() { | |
| 1492 // When we check for default browser we don't necessarily want to count file | |
| 1493 // type handlers and icons as having changed the default browser status, | |
| 1494 // since the user may have changed their shell settings to cause HTML files | |
| 1495 // to open with a text editor for example. We also don't want to aggressively | |
| 1496 // claim FTP, since the user may have a separate FTP client. It is an open | |
| 1497 // question as to how to "heal" these settings. Perhaps the user should just | |
| 1498 // re-run the installer or run with the --set-default-browser command line | |
| 1499 // flag. There is doubtless some other key we can hook into to cause "Repair" | |
| 1500 // to show up in Add/Remove programs for us. | |
| 1501 static const wchar_t* const kChromeProtocols[] = { L"http", L"https" }; | |
| 1502 return ProbeProtocolHandlers(kChromeProtocols, arraysize(kChromeProtocols)); | |
| 1503 } | |
| 1504 | |
| 1505 ShellUtil::DefaultState ShellUtil::IsChromeDefaultProtocolClient( | |
| 1506 const string16& protocol) { | |
| 1507 if (protocol.empty()) | |
| 1508 return UNKNOWN_DEFAULT; | |
| 1509 | |
| 1510 const wchar_t* const protocols[] = { protocol.c_str() }; | |
| 1511 return ProbeProtocolHandlers(protocols, arraysize(protocols)); | |
| 1512 } | |
| 1513 | |
| 1339 // static | 1514 // static |
| 1340 bool ShellUtil::CanMakeChromeDefaultUnattended() { | 1515 bool ShellUtil::CanMakeChromeDefaultUnattended() { |
| 1341 return base::win::GetVersion() < base::win::VERSION_WIN8; | 1516 return base::win::GetVersion() < base::win::VERSION_WIN8; |
| 1342 } | 1517 } |
| 1343 | 1518 |
| 1344 bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist, | 1519 bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist, |
| 1345 int shell_change, | 1520 int shell_change, |
| 1346 const string16& chrome_exe, | 1521 const string16& chrome_exe, |
| 1347 bool elevate_if_not_admin) { | 1522 bool elevate_if_not_admin) { |
| 1348 DCHECK(!(shell_change & ShellUtil::SYSTEM_LEVEL) || IsUserAnAdmin()); | 1523 DCHECK(!(shell_change & ShellUtil::SYSTEM_LEVEL) || IsUserAnAdmin()); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1736 // are any left...). | 1911 // are any left...). |
| 1737 if (free_bits >= 8 && next_byte_index < size) { | 1912 if (free_bits >= 8 && next_byte_index < size) { |
| 1738 free_bits -= 8; | 1913 free_bits -= 8; |
| 1739 bit_stream += bytes[next_byte_index++] << free_bits; | 1914 bit_stream += bytes[next_byte_index++] << free_bits; |
| 1740 } | 1915 } |
| 1741 } | 1916 } |
| 1742 | 1917 |
| 1743 DCHECK_EQ(ret.length(), encoded_length); | 1918 DCHECK_EQ(ret.length(), encoded_length); |
| 1744 return ret; | 1919 return ret; |
| 1745 } | 1920 } |
| OLD | NEW |