blob: f4c8609f43ec88bc8c84e97eb715f7ec009cafb8 [file] [log] [blame]
[email protected]b6b72222012-02-11 02:04:131// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d24c4012009-07-28 01:57:312// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/shell_integration.h"
6
7#include <windows.h>
[email protected]d24c4012009-07-28 01:57:318#include <shobjidl.h>
[email protected]935aa542010-10-15 01:59:159#include <propkey.h>
10#include <propvarutil.h>
[email protected]d24c4012009-07-28 01:57:3111
[email protected]3a3e72c2011-11-29 02:59:3812#include "base/bind.h"
[email protected]d24c4012009-07-28 01:57:3113#include "base/command_line.h"
14#include "base/file_util.h"
15#include "base/message_loop.h"
16#include "base/path_service.h"
[email protected]43903b82012-06-01 05:26:2317#include "base/scoped_native_library.h"
[email protected]2de2d622011-10-21 22:07:3718#include "base/string_number_conversions.h"
[email protected]d24c4012009-07-28 01:57:3119#include "base/string_util.h"
[email protected]33272e1f02011-08-17 00:22:0720#include "base/stringprintf.h"
[email protected]57ecc4b2010-08-11 03:02:5121#include "base/utf_string_conversions.h"
[email protected]43903b82012-06-01 05:26:2322#include "base/win/metro.h"
[email protected]2d6503982010-10-17 04:41:5423#include "base/win/registry.h"
[email protected]ecbff382012-05-17 00:56:0624#include "base/win/scoped_co_mem.h"
[email protected]8ee65ba2011-04-12 20:53:2325#include "base/win/scoped_comptr.h"
[email protected]935aa542010-10-15 01:59:1526#include "base/win/windows_version.h"
[email protected]c9bb06f42010-01-13 23:53:4827#include "chrome/browser/web_applications/web_app.h"
[email protected]d24c4012009-07-28 01:57:3128#include "chrome/common/chrome_constants.h"
[email protected]12f520c2010-01-06 18:11:1529#include "chrome/common/chrome_paths.h"
30#include "chrome/common/chrome_paths_internal.h"
[email protected]c9bb06f42010-01-13 23:53:4831#include "chrome/common/chrome_switches.h"
[email protected]4468a5b2011-05-26 07:48:0232#include "chrome/installer/setup/setup_util.h"
[email protected]d24c4012009-07-28 01:57:3133#include "chrome/installer/util/browser_distribution.h"
34#include "chrome/installer/util/create_reg_key_work_item.h"
35#include "chrome/installer/util/set_reg_value_work_item.h"
36#include "chrome/installer/util/shell_util.h"
37#include "chrome/installer/util/util_constants.h"
38#include "chrome/installer/util/work_item.h"
39#include "chrome/installer/util/work_item_list.h"
[email protected]c38831a12011-10-28 12:44:4940#include "content/public/browser/browser_thread.h"
[email protected]d24c4012009-07-28 01:57:3141
[email protected]631bb742011-11-02 11:29:3942using content::BrowserThread;
43
[email protected]12f520c2010-01-06 18:11:1544namespace {
45
[email protected]ecbff382012-05-17 00:56:0646// Gets the short (8.3) form of |path|, putting the result in |short_path| and
47// returning true on success. |short_path| is not modified on failure.
48bool ShortNameFromPath(const FilePath& path, string16* short_path) {
49 DCHECK(short_path);
50 string16 result(MAX_PATH, L'\0');
51 DWORD short_length = GetShortPathName(path.value().c_str(), &result[0],
52 result.size());
53 if (short_length == 0 || short_length > result.size()) {
54 PLOG(ERROR) << "Error getting short (8.3) path";
55 return false;
56 }
57
58 result.resize(short_length);
59 short_path->swap(result);
60 return true;
61}
62
63// Probe using IApplicationAssociationRegistration::QueryCurrentDefault
64// (Windows 8); see ProbeProtocolHandlers. This mechanism is not suitable for
65// use on previous versions of Windows despite the presence of
66// QueryCurrentDefault on them since versions of Windows prior to Windows 8
67// did not perform validation on the ProgID registered as the current default.
68// As a result, stale ProgIDs could be returned, leading to false positives.
69ShellIntegration::DefaultWebClientState ProbeCurrentDefaultHandlers(
70 const wchar_t* const* protocols,
71 size_t num_protocols) {
72 base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
73 HRESULT hr = registration.CreateInstance(
74 CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
75 if (FAILED(hr))
76 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
77
78 string16 prog_id(ShellUtil::kChromeHTMLProgId);
79
80 // If a user specific default browser entry exists, we check for that ProgID
81 // being default. If not, then the ProgID is ChromeHTML or ChromiumHTML so we
82 // do not append a suffix to the ProgID.
83 string16 suffix;
84 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
85 if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
86 prog_id += suffix;
87
88 for (size_t i = 0; i < num_protocols; ++i) {
89 base::win::ScopedCoMem<wchar_t> current_app;
90 hr = registration->QueryCurrentDefault(protocols[i], AT_URLPROTOCOL,
91 AL_EFFECTIVE, &current_app);
92 if (FAILED(hr) || prog_id.compare(current_app) != 0)
93 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
94 }
95
96 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
97}
98
99// Probe using IApplicationAssociationRegistration::QueryAppIsDefault (Vista and
100// Windows 7); see ProbeProtocolHandlers.
101ShellIntegration::DefaultWebClientState ProbeAppIsDefaultHandlers(
102 const wchar_t* const* protocols,
103 size_t num_protocols) {
104 base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
105 HRESULT hr = registration.CreateInstance(
106 CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
107 if (FAILED(hr))
108 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
109
110 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
111 string16 app_name(dist->GetApplicationName());
112
113 // If a user specific default browser entry exists, we check for that
114 // app name being default. If not, then default browser is just called
115 // Google Chrome or Chromium so we do not append a suffix to the app name.
116 string16 suffix;
117 if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
118 app_name += suffix;
119
120 BOOL result;
121 for (size_t i = 0; i < num_protocols; ++i) {
122 result = TRUE;
123 hr = registration->QueryAppIsDefault(protocols[i], AT_URLPROTOCOL,
124 AL_EFFECTIVE, app_name.c_str(), &result);
125 if (FAILED(hr) || result == FALSE)
126 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
127 }
128
129 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
130}
131
132// Probe the current commands registered to handle the shell "open" verb for
133// |protocols| (Windows XP); see ProbeProtocolHandlers.
134ShellIntegration::DefaultWebClientState ProbeOpenCommandHandlers(
135 const wchar_t* const* protocols,
136 size_t num_protocols) {
137 // Get the path to the current exe (Chrome).
138 FilePath app_path;
139 if (!PathService::Get(base::FILE_EXE, &app_path)) {
140 LOG(ERROR) << "Error getting app exe path";
141 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
142 }
143
144 // Get its short (8.3) form.
145 string16 short_app_path;
146 if (!ShortNameFromPath(app_path, &short_app_path))
147 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
148
149 const HKEY root_key = HKEY_CLASSES_ROOT;
150 string16 key_path;
151 base::win::RegKey key;
152 string16 value;
153 CommandLine command_line(CommandLine::NO_PROGRAM);
154 string16 short_path;
155
156 for (size_t i = 0; i < num_protocols; ++i) {
157 // Get the command line from HKCU\<protocol>\shell\open\command.
158 key_path.assign(protocols[i]).append(ShellUtil::kRegShellOpen);
159 if ((key.Open(root_key, key_path.c_str(),
160 KEY_QUERY_VALUE) != ERROR_SUCCESS) ||
161 (key.ReadValue(L"", &value) != ERROR_SUCCESS)) {
162 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
163 }
164
165 // Need to normalize path in case it's been munged.
166 command_line = CommandLine::FromString(value);
167 if (!ShortNameFromPath(command_line.GetProgram(), &short_path))
168 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
169
170 if (!FilePath::CompareEqualIgnoreCase(short_path, short_app_path))
171 return ShellIntegration::NOT_DEFAULT_WEB_CLIENT;
172 }
173
174 return ShellIntegration::IS_DEFAULT_WEB_CLIENT;
175}
176
177// A helper function that probes default protocol handler registration (in a
178// manner appropriate for the current version of Windows) to determine if
179// Chrome is the default handler for |protocols|. Returns IS_DEFAULT_WEB_CLIENT
180// only if Chrome is the default for all specified protocols.
181ShellIntegration::DefaultWebClientState ProbeProtocolHandlers(
182 const wchar_t* const* protocols,
183 size_t num_protocols) {
184 DCHECK(!num_protocols || protocols);
185 if (DCHECK_IS_ON()) {
186 for (size_t i = 0; i < num_protocols; ++i)
187 DCHECK(protocols[i] && *protocols[i]);
188 }
189
190 const base::win::Version windows_version = base::win::GetVersion();
191
192 if (windows_version >= base::win::VERSION_WIN8)
193 return ProbeCurrentDefaultHandlers(protocols, num_protocols);
194 else if (windows_version >= base::win::VERSION_VISTA)
195 return ProbeAppIsDefaultHandlers(protocols, num_protocols);
196
197 return ProbeOpenCommandHandlers(protocols, num_protocols);
198}
199
[email protected]12f520c2010-01-06 18:11:15200// Helper function for ShellIntegration::GetAppId to generates profile id
[email protected]2f1c09d2011-01-14 14:58:14201// from profile path. "profile_id" is composed of sanitized basenames of
[email protected]12f520c2010-01-06 18:11:15202// user data dir and profile dir joined by a ".".
[email protected]b6b72222012-02-11 02:04:13203string16 GetProfileIdFromPath(const FilePath& profile_path) {
[email protected]12f520c2010-01-06 18:11:15204 // Return empty string if profile_path is empty
205 if (profile_path.empty())
[email protected]b6b72222012-02-11 02:04:13206 return string16();
[email protected]12f520c2010-01-06 18:11:15207
208 FilePath default_user_data_dir;
209 // Return empty string if profile_path is in default user data
210 // dir and is the default profile.
211 if (chrome::GetDefaultUserDataDirectory(&default_user_data_dir) &&
212 profile_path.DirName() == default_user_data_dir &&
[email protected]162b5992011-03-15 19:40:48213 profile_path.BaseName().value() ==
[email protected]d778d6e2011-08-12 09:47:05214 ASCIIToUTF16(chrome::kInitialProfile)) {
[email protected]b6b72222012-02-11 02:04:13215 return string16();
[email protected]162b5992011-03-15 19:40:48216 }
[email protected]12f520c2010-01-06 18:11:15217
218 // Get joined basenames of user data dir and profile.
[email protected]b6b72222012-02-11 02:04:13219 string16 basenames = profile_path.DirName().BaseName().value() +
[email protected]12f520c2010-01-06 18:11:15220 L"." + profile_path.BaseName().value();
221
[email protected]b6b72222012-02-11 02:04:13222 string16 profile_id;
[email protected]12f520c2010-01-06 18:11:15223 profile_id.reserve(basenames.size());
224
225 // Generate profile_id from sanitized basenames.
226 for (size_t i = 0; i < basenames.length(); ++i) {
227 if (IsAsciiAlpha(basenames[i]) ||
228 IsAsciiDigit(basenames[i]) ||
229 basenames[i] == L'.')
230 profile_id += basenames[i];
231 }
232
233 return profile_id;
234}
235
[email protected]b6b72222012-02-11 02:04:13236bool GetShortcutAppId(IShellLink* shell_link, string16* app_id) {
[email protected]3a3e72c2011-11-29 02:59:38237 DCHECK(shell_link);
238 DCHECK(app_id);
[email protected]c9bb06f42010-01-13 23:53:48239
[email protected]3a3e72c2011-11-29 02:59:38240 app_id->clear();
[email protected]c9bb06f42010-01-13 23:53:48241
[email protected]3a3e72c2011-11-29 02:59:38242 base::win::ScopedComPtr<IPropertyStore> property_store;
243 if (FAILED(property_store.QueryFrom(shell_link)))
244 return false;
[email protected]c9bb06f42010-01-13 23:53:48245
[email protected]3a3e72c2011-11-29 02:59:38246 PROPVARIANT appid_value;
247 PropVariantInit(&appid_value);
248 if (FAILED(property_store->GetValue(PKEY_AppUserModel_ID, &appid_value)))
249 return false;
[email protected]c9bb06f42010-01-13 23:53:48250
[email protected]3a3e72c2011-11-29 02:59:38251 if (appid_value.vt == VT_LPWSTR || appid_value.vt == VT_BSTR)
252 app_id->assign(appid_value.pwszVal);
[email protected]c9bb06f42010-01-13 23:53:48253
[email protected]3a3e72c2011-11-29 02:59:38254 PropVariantClear(&appid_value);
255 return true;
[email protected]c9bb06f42010-01-13 23:53:48256}
257
[email protected]3a3e72c2011-11-29 02:59:38258// Gets expected app id for given chrome shortcut. Returns true if the shortcut
259// points to chrome and expected app id is successfully derived.
260bool GetExpectedAppId(const FilePath& chrome_exe,
261 IShellLink* shell_link,
[email protected]b6b72222012-02-11 02:04:13262 string16* expected_app_id) {
[email protected]c9bb06f42010-01-13 23:53:48263 DCHECK(shell_link);
264 DCHECK(expected_app_id);
265
266 expected_app_id->clear();
267
268 // Check if the shortcut points to chrome_exe.
[email protected]b6b72222012-02-11 02:04:13269 string16 source;
[email protected]3a3e72c2011-11-29 02:59:38270 if (FAILED(shell_link->GetPath(WriteInto(&source, MAX_PATH), MAX_PATH, NULL,
[email protected]c9bb06f42010-01-13 23:53:48271 SLGP_RAWPATH)) ||
[email protected]3a3e72c2011-11-29 02:59:38272 lstrcmpi(chrome_exe.value().c_str(), source.c_str()))
[email protected]c9bb06f42010-01-13 23:53:48273 return false;
274
[email protected]b6b72222012-02-11 02:04:13275 string16 arguments;
[email protected]c9bb06f42010-01-13 23:53:48276 if (FAILED(shell_link->GetArguments(WriteInto(&arguments, MAX_PATH),
277 MAX_PATH)))
278 return false;
279
280 // Get expected app id from shortcut command line.
[email protected]33272e1f02011-08-17 00:22:07281 CommandLine command_line = CommandLine::FromString(base::StringPrintf(
[email protected]c9bb06f42010-01-13 23:53:48282 L"\"%ls\" %ls", source.c_str(), arguments.c_str()));
283
284 FilePath profile_path;
285 if (command_line.HasSwitch(switches::kUserDataDir)) {
[email protected]660e428f2010-08-04 01:23:00286 profile_path =
[email protected]162b5992011-03-15 19:40:48287 command_line.GetSwitchValuePath(switches::kUserDataDir).AppendASCII(
[email protected]d778d6e2011-08-12 09:47:05288 chrome::kInitialProfile);
[email protected]c9bb06f42010-01-13 23:53:48289 }
290
[email protected]b6b72222012-02-11 02:04:13291 string16 app_name;
[email protected]c9bb06f42010-01-13 23:53:48292 if (command_line.HasSwitch(switches::kApp)) {
[email protected]b6b72222012-02-11 02:04:13293 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromURL(
[email protected]57ecc4b2010-08-11 03:02:51294 GURL(command_line.GetSwitchValueASCII(switches::kApp))));
[email protected]2f1c09d2011-01-14 14:58:14295 } else if (command_line.HasSwitch(switches::kAppId)) {
[email protected]b6b72222012-02-11 02:04:13296 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId(
[email protected]2f1c09d2011-01-14 14:58:14297 command_line.GetSwitchValueASCII(switches::kAppId)));
[email protected]c9bb06f42010-01-13 23:53:48298 } else {
[email protected]1caa92612010-06-11 00:13:56299 app_name = BrowserDistribution::GetDistribution()->GetBrowserAppId();
[email protected]c9bb06f42010-01-13 23:53:48300 }
301
[email protected]1caa92612010-06-11 00:13:56302 expected_app_id->assign(ShellIntegration::GetAppId(app_name, profile_path));
[email protected]c9bb06f42010-01-13 23:53:48303 return true;
304}
305
[email protected]3a3e72c2011-11-29 02:59:38306void MigrateWin7ShortcutsInPath(
307 const FilePath& chrome_exe, const FilePath& path) {
308 // Enumerate all pinned shortcuts in the given path directly.
309 file_util::FileEnumerator shortcuts_enum(
310 path, false, // not recursive
311 file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk"));
[email protected]c9bb06f42010-01-13 23:53:48312
[email protected]3a3e72c2011-11-29 02:59:38313 for (FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty();
314 shortcut = shortcuts_enum.Next()) {
315 // Load the shortcut.
316 base::win::ScopedComPtr<IShellLink> shell_link;
317 if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL,
318 CLSCTX_INPROC_SERVER))) {
319 NOTREACHED();
320 return;
321 }
[email protected]c9bb06f42010-01-13 23:53:48322
[email protected]3a3e72c2011-11-29 02:59:38323 base::win::ScopedComPtr<IPersistFile> persist_file;
324 if (FAILED(persist_file.QueryFrom(shell_link)) ||
325 FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) {
326 NOTREACHED();
327 return;
328 }
[email protected]c9bb06f42010-01-13 23:53:48329
[email protected]3a3e72c2011-11-29 02:59:38330 // Get expected app id from shortcut.
[email protected]b6b72222012-02-11 02:04:13331 string16 expected_app_id;
[email protected]3a3e72c2011-11-29 02:59:38332 if (!GetExpectedAppId(chrome_exe, shell_link, &expected_app_id) ||
333 expected_app_id.empty())
334 continue;
[email protected]c9bb06f42010-01-13 23:53:48335
[email protected]3a3e72c2011-11-29 02:59:38336 // Get existing app id from shortcut if any.
[email protected]b6b72222012-02-11 02:04:13337 string16 existing_app_id;
[email protected]3a3e72c2011-11-29 02:59:38338 GetShortcutAppId(shell_link, &existing_app_id);
[email protected]c9bb06f42010-01-13 23:53:48339
[email protected]3a3e72c2011-11-29 02:59:38340 if (expected_app_id != existing_app_id) {
[email protected]2e1a4a82012-04-06 19:23:11341 file_util::CreateOrUpdateShortcutLink(NULL, shortcut.value().c_str(),
342 NULL, NULL, NULL, NULL, 0,
343 expected_app_id.c_str(),
344 file_util::SHORTCUT_NO_OPTIONS);
[email protected]3a3e72c2011-11-29 02:59:38345 }
346 }
[email protected]c9bb06f42010-01-13 23:53:48347}
348
[email protected]3a3e72c2011-11-29 02:59:38349void MigrateChromiumShortcutsCallback() {
350 // This should run on the file thread.
351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
352
353 // Get full path of chrome.
354 FilePath chrome_exe;
355 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
356 return;
357
358 // Locations to check for shortcuts migration.
359 static const struct {
360 int location_id;
361 const wchar_t* sub_dir;
362 } kLocations[] = {
363 {
364 base::DIR_APP_DATA,
365 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar"
366 }, {
367 chrome::DIR_USER_DESKTOP,
368 NULL
369 }, {
370 base::DIR_START_MENU,
371 NULL
372 }, {
373 base::DIR_APP_DATA,
374 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
375 }
376 };
377
378 for (int i = 0; i < arraysize(kLocations); ++i) {
379 FilePath path;
380 if (!PathService::Get(kLocations[i].location_id, &path)) {
381 NOTREACHED();
382 continue;
383 }
384
385 if (kLocations[i].sub_dir)
386 path = path.Append(kLocations[i].sub_dir);
387
388 MigrateWin7ShortcutsInPath(chrome_exe, path);
389 }
390}
391
[email protected]43903b82012-06-01 05:26:23392// Activates the application with the given AppUserModelId.
393bool ActivateApplication(const string16& app_id) {
394 // Not supported when running in metro mode.
395 // TODO(grt) This should perhaps check that this Chrome isn't in metro mode
396 // or, if it is, that |app_id| doesn't identify this Chrome.
397 if (base::win::GetMetroModule())
398 return false;
399
400 // Delegate to metro_driver, which has the brains to invoke the activation
401 // wizardry.
402 bool success = false;
403 const FilePath metro_driver_path(chrome::kMetroDriverDll);
404 base::ScopedNativeLibrary metro_driver(metro_driver_path);
405 if (!metro_driver.is_valid()) {
406 PLOG(ERROR) << "Failed to load metro_driver.";
407 } else {
408 base::win::ActivateApplicationFn activate_application =
409 reinterpret_cast<base::win::ActivateApplicationFn>(
410 metro_driver.GetFunctionPointer(base::win::kActivateApplication));
411 if (!activate_application) {
412 PLOG(ERROR) << "Failed to find activation method in metro_driver.";
413 } else {
414 HRESULT hr = activate_application(app_id.c_str());
415 if (FAILED(hr)) {
416 LOG(ERROR) << "Failed to activate " << app_id
417 << "; hr=0x" << std::hex << hr;
418 } else {
419 success = true;
420 }
421 }
422 }
423 return success;
424}
425
[email protected]3a3e72c2011-11-29 02:59:38426} // namespace
[email protected]12f520c2010-01-06 18:11:15427
[email protected]a01481b2011-07-15 04:30:02428bool ShellIntegration::CanSetAsDefaultBrowser() {
429 return BrowserDistribution::GetDistribution()->CanSetAsDefault();
430}
431
[email protected]d24c4012009-07-28 01:57:31432bool ShellIntegration::SetAsDefaultBrowser() {
[email protected]b9696482010-11-30 23:56:18433 FilePath chrome_exe;
[email protected]d24c4012009-07-28 01:57:31434 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
435 LOG(ERROR) << "Error getting app exe path";
436 return false;
437 }
438
439 // From UI currently we only allow setting default browser for current user.
[email protected]bf6117c7e2010-12-01 06:00:25440 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
441 if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
[email protected]b9696482010-11-30 23:56:18442 chrome_exe.value(), true)) {
[email protected]d24c4012009-07-28 01:57:31443 LOG(ERROR) << "Chrome could not be set as default browser.";
444 return false;
445 }
446
[email protected]8e96e502010-10-21 20:57:12447 VLOG(1) << "Chrome registered as default browser.";
[email protected]d24c4012009-07-28 01:57:31448 return true;
449}
450
[email protected]4468a5b2011-05-26 07:48:02451bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) {
452 if (protocol.empty())
453 return false;
454
455 FilePath chrome_exe;
456 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
457 LOG(ERROR) << "Error getting app exe path";
458 return false;
459 }
460
[email protected]b6b72222012-02-11 02:04:13461 string16 wprotocol = UTF8ToUTF16(protocol);
[email protected]4468a5b2011-05-26 07:48:02462 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
463 if (!ShellUtil::MakeChromeDefaultProtocolClient(dist, chrome_exe.value(),
464 wprotocol)) {
465 LOG(ERROR) << "Chrome could not be set as default handler for "
466 << protocol << ".";
467 return false;
468 }
469
470 VLOG(1) << "Chrome registered as default handler for " << protocol << ".";
471 return true;
472}
473
474ShellIntegration::DefaultWebClientState ShellIntegration::IsDefaultBrowser() {
[email protected]d24c4012009-07-28 01:57:31475 // When we check for default browser we don't necessarily want to count file
476 // type handlers and icons as having changed the default browser status,
477 // since the user may have changed their shell settings to cause HTML files
478 // to open with a text editor for example. We also don't want to aggressively
479 // claim FTP, since the user may have a separate FTP client. It is an open
480 // question as to how to "heal" these settings. Perhaps the user should just
481 // re-run the installer or run with the --set-default-browser command line
482 // flag. There is doubtless some other key we can hook into to cause "Repair"
483 // to show up in Add/Remove programs for us.
[email protected]ecbff382012-05-17 00:56:06484 static const wchar_t* const kChromeProtocols[] = { L"http", L"https" };
[email protected]d24c4012009-07-28 01:57:31485
[email protected]ecbff382012-05-17 00:56:06486 return ProbeProtocolHandlers(kChromeProtocols, arraysize(kChromeProtocols));
[email protected]4468a5b2011-05-26 07:48:02487}
488
489ShellIntegration::DefaultWebClientState
490 ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) {
491 if (protocol.empty())
492 return UNKNOWN_DEFAULT_WEB_CLIENT;
493
[email protected]ecbff382012-05-17 00:56:06494 string16 wide_protocol(UTF8ToUTF16(protocol));
495 const wchar_t* const protocols[] = { wide_protocol.c_str() };
[email protected]4468a5b2011-05-26 07:48:02496
[email protected]ecbff382012-05-17 00:56:06497 return ProbeProtocolHandlers(protocols, arraysize(protocols));
[email protected]d24c4012009-07-28 01:57:31498}
499
500// There is no reliable way to say which browser is default on a machine (each
501// browser can have some of the protocols/shortcuts). So we look for only HTTP
502// protocol handler. Even this handler is located at different places in
503// registry on XP and Vista:
504// - HKCR\http\shell\open\command (XP)
505// - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\
506// http\UserChoice (Vista)
507// This method checks if Firefox is defualt browser by checking these
508// locations and returns true if Firefox traces are found there. In case of
509// error (or if Firefox is not found)it returns the default value which
510// is false.
511bool ShellIntegration::IsFirefoxDefaultBrowser() {
512 bool ff_default = false;
[email protected]935aa542010-10-15 01:59:15513 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
[email protected]b6b72222012-02-11 02:04:13514 string16 app_cmd;
[email protected]2d6503982010-10-17 04:41:54515 base::win::RegKey key(HKEY_CURRENT_USER,
516 ShellUtil::kRegVistaUrlPrefs, KEY_READ);
[email protected]e06f4d52011-01-19 07:28:46517 if (key.Valid() && (key.ReadValue(L"Progid", &app_cmd) == ERROR_SUCCESS) &&
[email protected]d24c4012009-07-28 01:57:31518 app_cmd == L"FirefoxURL")
519 ff_default = true;
520 } else {
[email protected]b6b72222012-02-11 02:04:13521 string16 key_path(L"http");
[email protected]d24c4012009-07-28 01:57:31522 key_path.append(ShellUtil::kRegShellOpen);
[email protected]2d6503982010-10-17 04:41:54523 base::win::RegKey key(HKEY_CLASSES_ROOT, key_path.c_str(), KEY_READ);
[email protected]b6b72222012-02-11 02:04:13524 string16 app_cmd;
[email protected]e06f4d52011-01-19 07:28:46525 if (key.Valid() && (key.ReadValue(L"", &app_cmd) == ERROR_SUCCESS) &&
[email protected]b6b72222012-02-11 02:04:13526 string16::npos != StringToLowerASCII(app_cmd).find(L"firefox"))
[email protected]d24c4012009-07-28 01:57:31527 ff_default = true;
528 }
529 return ff_default;
530}
[email protected]12f520c2010-01-06 18:11:15531
[email protected]b6b72222012-02-11 02:04:13532string16 ShellIntegration::GetAppId(const string16& app_name,
533 const FilePath& profile_path) {
534 string16 app_id(app_name);
[email protected]12f520c2010-01-06 18:11:15535
[email protected]b6b72222012-02-11 02:04:13536 string16 profile_id(GetProfileIdFromPath(profile_path));
[email protected]12f520c2010-01-06 18:11:15537 if (!profile_id.empty()) {
538 app_id += L".";
539 app_id += profile_id;
540 }
541
542 // App id should be less than 128 chars.
543 DCHECK(app_id.length() < 128);
544 return app_id;
545}
546
[email protected]b6b72222012-02-11 02:04:13547string16 ShellIntegration::GetChromiumAppId(const FilePath& profile_path) {
[email protected]1caa92612010-06-11 00:13:56548 return GetAppId(BrowserDistribution::GetDistribution()->GetBrowserAppId(),
549 profile_path);
[email protected]12f520c2010-01-06 18:11:15550}
[email protected]c9bb06f42010-01-13 23:53:48551
[email protected]2de2d622011-10-21 22:07:37552string16 ShellIntegration::GetChromiumIconPath() {
553 // Determine the app path. If we can't determine what that is, we have
554 // bigger fish to fry...
555 FilePath app_path;
556 if (!PathService::Get(base::FILE_EXE, &app_path)) {
557 NOTREACHED();
558 return string16();
559 }
560
561 string16 icon_path(app_path.value());
562 icon_path.push_back(',');
563 icon_path += base::IntToString16(
564 BrowserDistribution::GetDistribution()->GetIconIndex());
565 return icon_path;
566}
567
[email protected]c9bb06f42010-01-13 23:53:48568void ShellIntegration::MigrateChromiumShortcuts() {
[email protected]935aa542010-10-15 01:59:15569 if (base::win::GetVersion() < base::win::VERSION_WIN7)
[email protected]c9bb06f42010-01-13 23:53:48570 return;
571
[email protected]0c7d74f2010-10-11 11:55:26572 BrowserThread::PostTask(
[email protected]3a3e72c2011-11-29 02:59:38573 BrowserThread::FILE, FROM_HERE,
574 base::Bind(&MigrateChromiumShortcutsCallback));
[email protected]c9bb06f42010-01-13 23:53:48575}
[email protected]43903b82012-06-01 05:26:23576
577bool ShellIntegration::ActivateMetroChrome() {
578 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
579 const string16 app_id(dist->GetBrowserAppId());
580 return ActivateApplication(app_id);
581}