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

Side by Side Diff: chrome/browser/shell_integration_win.cc

Issue 11127002: Move "default for protocol" probing logic out of shell_integration_win.cc into shell_util.cc. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: better order in enum Created 8 years, 2 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/installer/util/shell_util.h » ('j') | chrome/installer/util/shell_util.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "chrome/browser/shell_integration.h" 5 #include "chrome/browser/shell_integration.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <shobjidl.h> 8 #include <shobjidl.h>
9 #include <propkey.h> 9 #include <propkey.h>
10 #include <propvarutil.h> 10 #include <propvarutil.h>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/file_util.h" 14 #include "base/file_util.h"
15 #include "base/message_loop.h" 15 #include "base/message_loop.h"
16 #include "base/path_service.h" 16 #include "base/path_service.h"
17 #include "base/string_number_conversions.h" 17 #include "base/string_number_conversions.h"
18 #include "base/string_util.h" 18 #include "base/string_util.h"
19 #include "base/stringprintf.h" 19 #include "base/stringprintf.h"
20 #include "base/utf_string_conversions.h" 20 #include "base/utf_string_conversions.h"
21 #include "base/win/registry.h" 21 #include "base/win/registry.h"
22 #include "base/win/scoped_co_mem.h"
23 #include "base/win/scoped_comptr.h" 22 #include "base/win/scoped_comptr.h"
24 #include "base/win/shortcut.h" 23 #include "base/win/shortcut.h"
25 #include "base/win/windows_version.h" 24 #include "base/win/windows_version.h"
26 #include "chrome/browser/web_applications/web_app.h" 25 #include "chrome/browser/web_applications/web_app.h"
27 #include "chrome/common/chrome_constants.h" 26 #include "chrome/common/chrome_constants.h"
28 #include "chrome/common/chrome_paths_internal.h" 27 #include "chrome/common/chrome_paths_internal.h"
29 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
30 #include "chrome/installer/setup/setup_util.h" 29 #include "chrome/installer/setup/setup_util.h"
31 #include "chrome/installer/util/browser_distribution.h" 30 #include "chrome/installer/util/browser_distribution.h"
32 #include "chrome/installer/util/create_reg_key_work_item.h" 31 #include "chrome/installer/util/create_reg_key_work_item.h"
33 #include "chrome/installer/util/install_util.h" 32 #include "chrome/installer/util/install_util.h"
34 #include "chrome/installer/util/set_reg_value_work_item.h" 33 #include "chrome/installer/util/set_reg_value_work_item.h"
35 #include "chrome/installer/util/shell_util.h" 34 #include "chrome/installer/util/shell_util.h"
36 #include "chrome/installer/util/util_constants.h" 35 #include "chrome/installer/util/util_constants.h"
37 #include "chrome/installer/util/work_item.h" 36 #include "chrome/installer/util/work_item.h"
38 #include "chrome/installer/util/work_item_list.h" 37 #include "chrome/installer/util/work_item_list.h"
39 #include "content/public/browser/browser_thread.h" 38 #include "content/public/browser/browser_thread.h"
40 39
41 using content::BrowserThread; 40 using content::BrowserThread;
42 41
43 namespace { 42 namespace {
44 43
45 // Gets the short (8.3) form of |path|, putting the result in |short_path| and
46 // returning true on success. |short_path| is not modified on failure.
47 bool ShortNameFromPath(const FilePath& path, string16* short_path) {
48 DCHECK(short_path);
49 string16 result(MAX_PATH, L'\0');
50 DWORD short_length = GetShortPathName(path.value().c_str(), &result[0],
51 result.size());
52 if (short_length == 0 || short_length > result.size()) {
53 PLOG(ERROR) << "Error getting short (8.3) path";
54 return false;
55 }
56
57 result.resize(short_length);
58 short_path->swap(result);
59 return true;
60 }
61
62 // Probe using IApplicationAssociationRegistration::QueryCurrentDefault
63 // (Windows 8); see ProbeProtocolHandlers. This mechanism is not suitable for
64 // use on previous versions of Windows despite the presence of
65 // QueryCurrentDefault on them since versions of Windows prior to Windows 8
66 // did not perform validation on the ProgID registered as the current default.
67 // As a result, stale ProgIDs could be returned, leading to false positives.
68 ShellIntegration::DefaultWebClientState ProbeCurrentDefaultHandlers(
69 const wchar_t* const* protocols,
70 size_t num_protocols) {
71 base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
72 HRESULT hr = registration.CreateInstance(
73 CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
74 if (FAILED(hr))
75 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
76
77 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
78 FilePath chrome_exe;
79 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
80 NOTREACHED();
81 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
82 }
83 string16 prog_id(ShellUtil::kChromeHTMLProgId);
84 prog_id += ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe.value());
85
86 for (size_t i = 0; i < num_protocols; ++i) {
87 base::win::ScopedCoMem<wchar_t> current_app;
88 hr = registration->QueryCurrentDefault(protocols[i], AT_URLPROTOCOL,
89 AL_EFFECTIVE, &current_app);
90 if (FAILED(hr) || prog_id.compare(current_app) != 0)
91 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
92 }
93
94 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
95 }
96
97 // Probe using IApplicationAssociationRegistration::QueryAppIsDefault (Vista and
98 // Windows 7); see ProbeProtocolHandlers.
99 ShellIntegration::DefaultWebClientState ProbeAppIsDefaultHandlers(
100 const wchar_t* const* protocols,
101 size_t num_protocols) {
102 base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
103 HRESULT hr = registration.CreateInstance(
104 CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
105 if (FAILED(hr))
106 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
107
108 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
109 FilePath chrome_exe;
110 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
111 NOTREACHED();
112 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
113 }
114 string16 app_name(ShellUtil::GetApplicationName(dist, chrome_exe.value()));
115
116 BOOL result;
117 for (size_t i = 0; i < num_protocols; ++i) {
118 result = TRUE;
119 hr = registration->QueryAppIsDefault(protocols[i], AT_URLPROTOCOL,
120 AL_EFFECTIVE, app_name.c_str(), &result);
121 if (FAILED(hr) || result == FALSE)
122 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
123 }
124
125 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
126 }
127
128 // Probe the current commands registered to handle the shell "open" verb for
129 // |protocols| (Windows XP); see ProbeProtocolHandlers.
130 ShellIntegration::DefaultWebClientState ProbeOpenCommandHandlers(
131 const wchar_t* const* protocols,
132 size_t num_protocols) {
133 // Get the path to the current exe (Chrome).
134 FilePath app_path;
135 if (!PathService::Get(base::FILE_EXE, &app_path)) {
136 LOG(ERROR) << "Error getting app exe path";
137 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
138 }
139
140 // Get its short (8.3) form.
141 string16 short_app_path;
142 if (!ShortNameFromPath(app_path, &short_app_path))
143 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
144
145 const HKEY root_key = HKEY_CLASSES_ROOT;
146 string16 key_path;
147 base::win::RegKey key;
148 string16 value;
149 CommandLine command_line(CommandLine::NO_PROGRAM);
150 string16 short_path;
151
152 for (size_t i = 0; i < num_protocols; ++i) {
153 // Get the command line from HKCU\<protocol>\shell\open\command.
154 key_path.assign(protocols[i]).append(ShellUtil::kRegShellOpen);
155 if ((key.Open(root_key, key_path.c_str(),
156 KEY_QUERY_VALUE) != ERROR_SUCCESS) ||
157 (key.ReadValue(L"", &value) != ERROR_SUCCESS)) {
158 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
159 }
160
161 // Need to normalize path in case it's been munged.
162 command_line = CommandLine::FromString(value);
163 if (!ShortNameFromPath(command_line.GetProgram(), &short_path))
164 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
165
166 if (!FilePath::CompareEqualIgnoreCase(short_path, short_app_path))
167 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
168 }
169
170 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
171 }
172
173 // A helper function that probes default protocol handler registration (in a
174 // manner appropriate for the current version of Windows) to determine if
175 // Chrome is the default handler for |protocols|. Returns IS_DEFAULT_WEB_CLIENT
176 // only if Chrome is the default for all specified protocols.
177 ShellIntegration::DefaultWebClientState ProbeProtocolHandlers(
178 const wchar_t* const* protocols,
179 size_t num_protocols) {
180 DCHECK(!num_protocols || protocols);
181 if (DCHECK_IS_ON()) {
182 for (size_t i = 0; i < num_protocols; ++i)
183 DCHECK(protocols[i] && *protocols[i]);
184 }
185
186 const base::win::Version windows_version = base::win::GetVersion();
187
188 if (windows_version >= base::win::VERSION_WIN8)
189 return ProbeCurrentDefaultHandlers(protocols, num_protocols);
190 else if (windows_version >= base::win::VERSION_VISTA)
191 return ProbeAppIsDefaultHandlers(protocols, num_protocols);
192
193 return ProbeOpenCommandHandlers(protocols, num_protocols);
194 }
195
196 // Helper function for ShellIntegration::GetAppId to generates profile id 44 // Helper function for ShellIntegration::GetAppId to generates profile id
197 // from profile path. "profile_id" is composed of sanitized basenames of 45 // from profile path. "profile_id" is composed of sanitized basenames of
198 // user data dir and profile dir joined by a ".". 46 // user data dir and profile dir joined by a ".".
199 string16 GetProfileIdFromPath(const FilePath& profile_path) { 47 string16 GetProfileIdFromPath(const FilePath& profile_path) {
200 // Return empty string if profile_path is empty 48 // Return empty string if profile_path is empty
201 if (profile_path.empty()) 49 if (profile_path.empty())
202 return string16(); 50 return string16();
203 51
204 FilePath default_user_data_dir; 52 FilePath default_user_data_dir;
205 // Return empty string if profile_path is in default user data 53 // Return empty string if profile_path is in default user data
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 continue; 230 continue;
383 } 231 }
384 232
385 if (kLocations[i].sub_dir) 233 if (kLocations[i].sub_dir)
386 path = path.Append(kLocations[i].sub_dir); 234 path = path.Append(kLocations[i].sub_dir);
387 235
388 MigrateWin7ShortcutsInPath(chrome_exe, path); 236 MigrateWin7ShortcutsInPath(chrome_exe, path);
389 } 237 }
390 } 238 }
391 239
240 ShellIntegration::DefaultWebClientState
241 GetDefaultWebClientStateFromShellUtilDefaultState(
242 ShellUtil::DefaultState default_state) {
243 switch (default_state) {
244 case ShellUtil::NOT_DEFAULT:
245 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
246 case ShellUtil::IS_DEFAULT:
247 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
248 default:
249 DCHECK_EQ(ShellUtil::UNKNOWN_DEFAULT, default_state);
250 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
Nico 2012/10/15 17:09:24 nit: I believe it's preferable to list all cases e
gab 2012/10/15 17:45:33 I would have liked that, but this doesn't compile
scottmg 2012/10/15 18:04:23 4062 is off by default even at /W4 (we don't use /
251 }
252 }
253
392 } // namespace 254 } // namespace
393 255
394 ShellIntegration::DefaultWebClientSetPermission 256 ShellIntegration::DefaultWebClientSetPermission
395 ShellIntegration::CanSetAsDefaultBrowser() { 257 ShellIntegration::CanSetAsDefaultBrowser() {
396 if (!BrowserDistribution::GetDistribution()->CanSetAsDefault()) 258 if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
397 return SET_DEFAULT_NOT_ALLOWED; 259 return SET_DEFAULT_NOT_ALLOWED;
398 260
399 if (ShellUtil::CanMakeChromeDefaultUnattended()) 261 if (ShellUtil::CanMakeChromeDefaultUnattended())
400 return SET_DEFAULT_UNATTENDED; 262 return SET_DEFAULT_UNATTENDED;
401 else 263 else
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 dist, chrome_exe.value(), wprotocol)) { 337 dist, chrome_exe.value(), wprotocol)) {
476 LOG(ERROR) << "Failed to launch the set-default-client Windows UI."; 338 LOG(ERROR) << "Failed to launch the set-default-client Windows UI.";
477 return false; 339 return false;
478 } 340 }
479 341
480 VLOG(1) << "Set-default-client Windows UI completed."; 342 VLOG(1) << "Set-default-client Windows UI completed.";
481 return true; 343 return true;
482 } 344 }
483 345
484 ShellIntegration::DefaultWebClientState ShellIntegration::IsDefaultBrowser() { 346 ShellIntegration::DefaultWebClientState ShellIntegration::IsDefaultBrowser() {
485 // When we check for default browser we don't necessarily want to count file 347 return GetDefaultWebClientStateFromShellUtilDefaultState(
486 // type handlers and icons as having changed the default browser status, 348 ShellUtil::IsChromeDefault());
487 // since the user may have changed their shell settings to cause HTML files
488 // to open with a text editor for example. We also don't want to aggressively
489 // claim FTP, since the user may have a separate FTP client. It is an open
490 // question as to how to "heal" these settings. Perhaps the user should just
491 // re-run the installer or run with the --set-default-browser command line
492 // flag. There is doubtless some other key we can hook into to cause "Repair"
493 // to show up in Add/Remove programs for us.
494 static const wchar_t* const kChromeProtocols[] = { L"http", L"https" };
495
496 return ProbeProtocolHandlers(kChromeProtocols, arraysize(kChromeProtocols));
497 } 349 }
498 350
499 ShellIntegration::DefaultWebClientState 351 ShellIntegration::DefaultWebClientState
500 ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) { 352 ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) {
501 if (protocol.empty()) 353 return GetDefaultWebClientStateFromShellUtilDefaultState(
502 return UNKNOWN_DEFAULT_WEB_CLIENT; 354 ShellUtil::IsChromeDefaultProtocolClient(UTF8ToUTF16(protocol)));
503
504 string16 wide_protocol(UTF8ToUTF16(protocol));
505 const wchar_t* const protocols[] = { wide_protocol.c_str() };
506
507 return ProbeProtocolHandlers(protocols, arraysize(protocols));
508 } 355 }
509 356
510 // There is no reliable way to say which browser is default on a machine (each 357 // There is no reliable way to say which browser is default on a machine (each
511 // browser can have some of the protocols/shortcuts). So we look for only HTTP 358 // browser can have some of the protocols/shortcuts). So we look for only HTTP
512 // protocol handler. Even this handler is located at different places in 359 // protocol handler. Even this handler is located at different places in
513 // registry on XP and Vista: 360 // registry on XP and Vista:
514 // - HKCR\http\shell\open\command (XP) 361 // - HKCR\http\shell\open\command (XP)
515 // - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\ 362 // - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\
516 // http\UserChoice (Vista) 363 // http\UserChoice (Vista)
517 // This method checks if Firefox is defualt browser by checking these 364 // This method checks if Firefox is defualt browser by checking these
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 } 456 }
610 457
611 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name + 458 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name +
612 installer::kLnkExt); 459 installer::kLnkExt);
613 if (file_util::PathExists(shortcut)) 460 if (file_util::PathExists(shortcut))
614 return shortcut; 461 return shortcut;
615 } 462 }
616 463
617 return FilePath(); 464 return FilePath();
618 } 465 }
OLDNEW
« no previous file with comments | « no previous file | chrome/installer/util/shell_util.h » ('j') | chrome/installer/util/shell_util.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698