blob: 97dae75806498acaffa93f9fe612a14b9a903acc [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]2de2d622011-10-21 22:07:3717#include "base/string_number_conversions.h"
[email protected]d24c4012009-07-28 01:57:3118#include "base/string_util.h"
[email protected]33272e1f02011-08-17 00:22:0719#include "base/stringprintf.h"
[email protected]57ecc4b2010-08-11 03:02:5120#include "base/utf_string_conversions.h"
[email protected]2d6503982010-10-17 04:41:5421#include "base/win/registry.h"
[email protected]ecbff382012-05-17 00:56:0622#include "base/win/scoped_co_mem.h"
[email protected]8ee65ba2011-04-12 20:53:2323#include "base/win/scoped_comptr.h"
[email protected]935aa542010-10-15 01:59:1524#include "base/win/windows_version.h"
[email protected]c9bb06f42010-01-13 23:53:4825#include "chrome/browser/web_applications/web_app.h"
[email protected]d24c4012009-07-28 01:57:3126#include "chrome/common/chrome_constants.h"
[email protected]12f520c2010-01-06 18:11:1527#include "chrome/common/chrome_paths.h"
28#include "chrome/common/chrome_paths_internal.h"
[email protected]c9bb06f42010-01-13 23:53:4829#include "chrome/common/chrome_switches.h"
[email protected]4468a5b2011-05-26 07:48:0230#include "chrome/installer/setup/setup_util.h"
[email protected]d24c4012009-07-28 01:57:3131#include "chrome/installer/util/browser_distribution.h"
32#include "chrome/installer/util/create_reg_key_work_item.h"
[email protected]3f69d6e612012-08-03 18:52:2733#include "chrome/installer/util/install_util.h"
[email protected]d24c4012009-07-28 01:57:3134#include "chrome/installer/util/set_reg_value_work_item.h"
35#include "chrome/installer/util/shell_util.h"
36#include "chrome/installer/util/util_constants.h"
37#include "chrome/installer/util/work_item.h"
38#include "chrome/installer/util/work_item_list.h"
[email protected]c38831a12011-10-28 12:44:4939#include "content/public/browser/browser_thread.h"
[email protected]d24c4012009-07-28 01:57:3140
[email protected]631bb742011-11-02 11:29:3941using content::BrowserThread;
42
[email protected]12f520c2010-01-06 18:11:1543namespace {
44
[email protected]ecbff382012-05-17 00:56:0645// 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.
47bool 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.
68ShellIntegration::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
[email protected]ecbff382012-05-17 00:56:0677 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
[email protected]0cb3b252012-06-17 07:54:2478 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());
[email protected]ecbff382012-05-17 00:56:0685
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.
99ShellIntegration::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();
[email protected]0cb3b252012-06-17 07:54:24109 FilePath chrome_exe;
110 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
111 NOTREACHED();
112 return ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT;
113 }
[email protected]c2f0c942012-06-17 15:23:37114 string16 app_name(ShellUtil::GetApplicationName(dist, chrome_exe.value()));
[email protected]ecbff382012-05-17 00:56:06115
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.
130ShellIntegration::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.
177ShellIntegration::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
[email protected]12f520c2010-01-06 18:11:15196// Helper function for ShellIntegration::GetAppId to generates profile id
[email protected]2f1c09d2011-01-14 14:58:14197// from profile path. "profile_id" is composed of sanitized basenames of
[email protected]12f520c2010-01-06 18:11:15198// user data dir and profile dir joined by a ".".
[email protected]b6b72222012-02-11 02:04:13199string16 GetProfileIdFromPath(const FilePath& profile_path) {
[email protected]12f520c2010-01-06 18:11:15200 // Return empty string if profile_path is empty
201 if (profile_path.empty())
[email protected]b6b72222012-02-11 02:04:13202 return string16();
[email protected]12f520c2010-01-06 18:11:15203
204 FilePath default_user_data_dir;
205 // Return empty string if profile_path is in default user data
206 // dir and is the default profile.
207 if (chrome::GetDefaultUserDataDirectory(&default_user_data_dir) &&
208 profile_path.DirName() == default_user_data_dir &&
[email protected]162b5992011-03-15 19:40:48209 profile_path.BaseName().value() ==
[email protected]d778d6e2011-08-12 09:47:05210 ASCIIToUTF16(chrome::kInitialProfile)) {
[email protected]b6b72222012-02-11 02:04:13211 return string16();
[email protected]162b5992011-03-15 19:40:48212 }
[email protected]12f520c2010-01-06 18:11:15213
214 // Get joined basenames of user data dir and profile.
[email protected]b6b72222012-02-11 02:04:13215 string16 basenames = profile_path.DirName().BaseName().value() +
[email protected]12f520c2010-01-06 18:11:15216 L"." + profile_path.BaseName().value();
217
[email protected]b6b72222012-02-11 02:04:13218 string16 profile_id;
[email protected]12f520c2010-01-06 18:11:15219 profile_id.reserve(basenames.size());
220
221 // Generate profile_id from sanitized basenames.
222 for (size_t i = 0; i < basenames.length(); ++i) {
223 if (IsAsciiAlpha(basenames[i]) ||
224 IsAsciiDigit(basenames[i]) ||
225 basenames[i] == L'.')
226 profile_id += basenames[i];
227 }
228
229 return profile_id;
230}
231
[email protected]b6b72222012-02-11 02:04:13232bool GetShortcutAppId(IShellLink* shell_link, string16* app_id) {
[email protected]3a3e72c2011-11-29 02:59:38233 DCHECK(shell_link);
234 DCHECK(app_id);
[email protected]c9bb06f42010-01-13 23:53:48235
[email protected]3a3e72c2011-11-29 02:59:38236 app_id->clear();
[email protected]c9bb06f42010-01-13 23:53:48237
[email protected]3a3e72c2011-11-29 02:59:38238 base::win::ScopedComPtr<IPropertyStore> property_store;
239 if (FAILED(property_store.QueryFrom(shell_link)))
240 return false;
[email protected]c9bb06f42010-01-13 23:53:48241
[email protected]3a3e72c2011-11-29 02:59:38242 PROPVARIANT appid_value;
243 PropVariantInit(&appid_value);
244 if (FAILED(property_store->GetValue(PKEY_AppUserModel_ID, &appid_value)))
245 return false;
[email protected]c9bb06f42010-01-13 23:53:48246
[email protected]3a3e72c2011-11-29 02:59:38247 if (appid_value.vt == VT_LPWSTR || appid_value.vt == VT_BSTR)
248 app_id->assign(appid_value.pwszVal);
[email protected]c9bb06f42010-01-13 23:53:48249
[email protected]3a3e72c2011-11-29 02:59:38250 PropVariantClear(&appid_value);
251 return true;
[email protected]c9bb06f42010-01-13 23:53:48252}
253
[email protected]3a3e72c2011-11-29 02:59:38254// Gets expected app id for given chrome shortcut. Returns true if the shortcut
255// points to chrome and expected app id is successfully derived.
256bool GetExpectedAppId(const FilePath& chrome_exe,
257 IShellLink* shell_link,
[email protected]b6b72222012-02-11 02:04:13258 string16* expected_app_id) {
[email protected]c9bb06f42010-01-13 23:53:48259 DCHECK(shell_link);
260 DCHECK(expected_app_id);
261
262 expected_app_id->clear();
263
264 // Check if the shortcut points to chrome_exe.
[email protected]b6b72222012-02-11 02:04:13265 string16 source;
[email protected]3a3e72c2011-11-29 02:59:38266 if (FAILED(shell_link->GetPath(WriteInto(&source, MAX_PATH), MAX_PATH, NULL,
[email protected]c9bb06f42010-01-13 23:53:48267 SLGP_RAWPATH)) ||
[email protected]3a3e72c2011-11-29 02:59:38268 lstrcmpi(chrome_exe.value().c_str(), source.c_str()))
[email protected]c9bb06f42010-01-13 23:53:48269 return false;
270
[email protected]b6b72222012-02-11 02:04:13271 string16 arguments;
[email protected]c9bb06f42010-01-13 23:53:48272 if (FAILED(shell_link->GetArguments(WriteInto(&arguments, MAX_PATH),
273 MAX_PATH)))
274 return false;
275
276 // Get expected app id from shortcut command line.
[email protected]33272e1f02011-08-17 00:22:07277 CommandLine command_line = CommandLine::FromString(base::StringPrintf(
[email protected]c9bb06f42010-01-13 23:53:48278 L"\"%ls\" %ls", source.c_str(), arguments.c_str()));
279
280 FilePath profile_path;
281 if (command_line.HasSwitch(switches::kUserDataDir)) {
[email protected]660e428f2010-08-04 01:23:00282 profile_path =
[email protected]162b5992011-03-15 19:40:48283 command_line.GetSwitchValuePath(switches::kUserDataDir).AppendASCII(
[email protected]d778d6e2011-08-12 09:47:05284 chrome::kInitialProfile);
[email protected]c9bb06f42010-01-13 23:53:48285 }
286
[email protected]b6b72222012-02-11 02:04:13287 string16 app_name;
[email protected]c9bb06f42010-01-13 23:53:48288 if (command_line.HasSwitch(switches::kApp)) {
[email protected]b6b72222012-02-11 02:04:13289 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromURL(
[email protected]57ecc4b2010-08-11 03:02:51290 GURL(command_line.GetSwitchValueASCII(switches::kApp))));
[email protected]2f1c09d2011-01-14 14:58:14291 } else if (command_line.HasSwitch(switches::kAppId)) {
[email protected]b6b72222012-02-11 02:04:13292 app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId(
[email protected]2f1c09d2011-01-14 14:58:14293 command_line.GetSwitchValueASCII(switches::kAppId)));
[email protected]c9bb06f42010-01-13 23:53:48294 } else {
[email protected]a0448002012-06-19 04:32:10295 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
296 app_name = ShellUtil::GetBrowserModelId(dist, chrome_exe.value());
[email protected]c9bb06f42010-01-13 23:53:48297 }
298
[email protected]a0448002012-06-19 04:32:10299 expected_app_id->assign(
300 ShellIntegration::GetAppModelIdForProfile(app_name, profile_path));
[email protected]c9bb06f42010-01-13 23:53:48301 return true;
302}
303
[email protected]3a3e72c2011-11-29 02:59:38304void MigrateWin7ShortcutsInPath(
305 const FilePath& chrome_exe, const FilePath& path) {
306 // Enumerate all pinned shortcuts in the given path directly.
307 file_util::FileEnumerator shortcuts_enum(
308 path, false, // not recursive
309 file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk"));
[email protected]c9bb06f42010-01-13 23:53:48310
[email protected]3a3e72c2011-11-29 02:59:38311 for (FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty();
312 shortcut = shortcuts_enum.Next()) {
313 // Load the shortcut.
314 base::win::ScopedComPtr<IShellLink> shell_link;
315 if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL,
316 CLSCTX_INPROC_SERVER))) {
317 NOTREACHED();
318 return;
319 }
[email protected]c9bb06f42010-01-13 23:53:48320
[email protected]3a3e72c2011-11-29 02:59:38321 base::win::ScopedComPtr<IPersistFile> persist_file;
322 if (FAILED(persist_file.QueryFrom(shell_link)) ||
323 FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) {
324 NOTREACHED();
325 return;
326 }
[email protected]c9bb06f42010-01-13 23:53:48327
[email protected]3a3e72c2011-11-29 02:59:38328 // Get expected app id from shortcut.
[email protected]b6b72222012-02-11 02:04:13329 string16 expected_app_id;
[email protected]3a3e72c2011-11-29 02:59:38330 if (!GetExpectedAppId(chrome_exe, shell_link, &expected_app_id) ||
331 expected_app_id.empty())
332 continue;
[email protected]c9bb06f42010-01-13 23:53:48333
[email protected]3a3e72c2011-11-29 02:59:38334 // Get existing app id from shortcut if any.
[email protected]b6b72222012-02-11 02:04:13335 string16 existing_app_id;
[email protected]3a3e72c2011-11-29 02:59:38336 GetShortcutAppId(shell_link, &existing_app_id);
[email protected]c9bb06f42010-01-13 23:53:48337
[email protected]3a3e72c2011-11-29 02:59:38338 if (expected_app_id != existing_app_id) {
[email protected]cfc84152012-09-11 02:46:08339 file_util::CreateOrUpdateShortcutLink(NULL, shortcut.value().c_str(),
340 NULL, NULL, NULL, NULL, 0,
341 expected_app_id.c_str(),
342 file_util::SHORTCUT_NO_OPTIONS);
[email protected]3a3e72c2011-11-29 02:59:38343 }
344 }
[email protected]c9bb06f42010-01-13 23:53:48345}
346
[email protected]3a3e72c2011-11-29 02:59:38347void MigrateChromiumShortcutsCallback() {
348 // This should run on the file thread.
349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
350
351 // Get full path of chrome.
352 FilePath chrome_exe;
353 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
354 return;
355
356 // Locations to check for shortcuts migration.
357 static const struct {
358 int location_id;
359 const wchar_t* sub_dir;
360 } kLocations[] = {
361 {
362 base::DIR_APP_DATA,
363 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar"
364 }, {
365 chrome::DIR_USER_DESKTOP,
366 NULL
367 }, {
368 base::DIR_START_MENU,
369 NULL
370 }, {
371 base::DIR_APP_DATA,
372 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
373 }
374 };
375
376 for (int i = 0; i < arraysize(kLocations); ++i) {
377 FilePath path;
378 if (!PathService::Get(kLocations[i].location_id, &path)) {
379 NOTREACHED();
380 continue;
381 }
382
383 if (kLocations[i].sub_dir)
384 path = path.Append(kLocations[i].sub_dir);
385
386 MigrateWin7ShortcutsInPath(chrome_exe, path);
387 }
388}
389
[email protected]3a3e72c2011-11-29 02:59:38390} // namespace
[email protected]12f520c2010-01-06 18:11:15391
[email protected]bd046bd42012-06-08 05:07:32392ShellIntegration::DefaultWebClientSetPermission
393 ShellIntegration::CanSetAsDefaultBrowser() {
394 if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
395 return SET_DEFAULT_NOT_ALLOWED;
396
[email protected]9fcf07f2012-06-18 16:13:51397 if (ShellUtil::CanMakeChromeDefaultUnattended())
[email protected]bd046bd42012-06-08 05:07:32398 return SET_DEFAULT_UNATTENDED;
[email protected]9fcf07f2012-06-18 16:13:51399 else
400 return SET_DEFAULT_INTERACTIVE;
[email protected]a01481b2011-07-15 04:30:02401}
402
[email protected]d24c4012009-07-28 01:57:31403bool ShellIntegration::SetAsDefaultBrowser() {
[email protected]b9696482010-11-30 23:56:18404 FilePath chrome_exe;
[email protected]d24c4012009-07-28 01:57:31405 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
406 LOG(ERROR) << "Error getting app exe path";
407 return false;
408 }
409
410 // From UI currently we only allow setting default browser for current user.
[email protected]bf6117c7e2010-12-01 06:00:25411 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
412 if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
[email protected]b9696482010-11-30 23:56:18413 chrome_exe.value(), true)) {
[email protected]d24c4012009-07-28 01:57:31414 LOG(ERROR) << "Chrome could not be set as default browser.";
415 return false;
416 }
417
[email protected]8e96e502010-10-21 20:57:12418 VLOG(1) << "Chrome registered as default browser.";
[email protected]d24c4012009-07-28 01:57:31419 return true;
420}
421
[email protected]4468a5b2011-05-26 07:48:02422bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) {
423 if (protocol.empty())
424 return false;
425
426 FilePath chrome_exe;
427 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
428 LOG(ERROR) << "Error getting app exe path";
429 return false;
430 }
431
[email protected]b6b72222012-02-11 02:04:13432 string16 wprotocol = UTF8ToUTF16(protocol);
[email protected]4468a5b2011-05-26 07:48:02433 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
434 if (!ShellUtil::MakeChromeDefaultProtocolClient(dist, chrome_exe.value(),
435 wprotocol)) {
436 LOG(ERROR) << "Chrome could not be set as default handler for "
437 << protocol << ".";
438 return false;
439 }
440
441 VLOG(1) << "Chrome registered as default handler for " << protocol << ".";
442 return true;
443}
444
[email protected]bd046bd42012-06-08 05:07:32445bool ShellIntegration::SetAsDefaultBrowserInteractive() {
446 FilePath chrome_exe;
447 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
448 NOTREACHED() << "Error getting app exe path";
449 return false;
450 }
451
452 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
453 if (!ShellUtil::ShowMakeChromeDefaultSystemUI(dist, chrome_exe.value())) {
454 LOG(ERROR) << "Failed to launch the set-default-browser Windows UI.";
455 return false;
456 }
457
458 VLOG(1) << "Set-as-default Windows UI triggered.";
459 return true;
460}
461
[email protected]4468a5b2011-05-26 07:48:02462ShellIntegration::DefaultWebClientState ShellIntegration::IsDefaultBrowser() {
[email protected]d24c4012009-07-28 01:57:31463 // When we check for default browser we don't necessarily want to count file
464 // type handlers and icons as having changed the default browser status,
465 // since the user may have changed their shell settings to cause HTML files
466 // to open with a text editor for example. We also don't want to aggressively
467 // claim FTP, since the user may have a separate FTP client. It is an open
468 // question as to how to "heal" these settings. Perhaps the user should just
469 // re-run the installer or run with the --set-default-browser command line
470 // flag. There is doubtless some other key we can hook into to cause "Repair"
471 // to show up in Add/Remove programs for us.
[email protected]ecbff382012-05-17 00:56:06472 static const wchar_t* const kChromeProtocols[] = { L"http", L"https" };
[email protected]d24c4012009-07-28 01:57:31473
[email protected]ecbff382012-05-17 00:56:06474 return ProbeProtocolHandlers(kChromeProtocols, arraysize(kChromeProtocols));
[email protected]4468a5b2011-05-26 07:48:02475}
476
477ShellIntegration::DefaultWebClientState
478 ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) {
479 if (protocol.empty())
480 return UNKNOWN_DEFAULT_WEB_CLIENT;
481
[email protected]ecbff382012-05-17 00:56:06482 string16 wide_protocol(UTF8ToUTF16(protocol));
483 const wchar_t* const protocols[] = { wide_protocol.c_str() };
[email protected]4468a5b2011-05-26 07:48:02484
[email protected]ecbff382012-05-17 00:56:06485 return ProbeProtocolHandlers(protocols, arraysize(protocols));
[email protected]d24c4012009-07-28 01:57:31486}
487
488// There is no reliable way to say which browser is default on a machine (each
489// browser can have some of the protocols/shortcuts). So we look for only HTTP
490// protocol handler. Even this handler is located at different places in
491// registry on XP and Vista:
492// - HKCR\http\shell\open\command (XP)
493// - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\
494// http\UserChoice (Vista)
495// This method checks if Firefox is defualt browser by checking these
496// locations and returns true if Firefox traces are found there. In case of
497// error (or if Firefox is not found)it returns the default value which
498// is false.
499bool ShellIntegration::IsFirefoxDefaultBrowser() {
500 bool ff_default = false;
[email protected]935aa542010-10-15 01:59:15501 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
[email protected]b6b72222012-02-11 02:04:13502 string16 app_cmd;
[email protected]2d6503982010-10-17 04:41:54503 base::win::RegKey key(HKEY_CURRENT_USER,
504 ShellUtil::kRegVistaUrlPrefs, KEY_READ);
[email protected]e06f4d52011-01-19 07:28:46505 if (key.Valid() && (key.ReadValue(L"Progid", &app_cmd) == ERROR_SUCCESS) &&
[email protected]d24c4012009-07-28 01:57:31506 app_cmd == L"FirefoxURL")
507 ff_default = true;
508 } else {
[email protected]b6b72222012-02-11 02:04:13509 string16 key_path(L"http");
[email protected]d24c4012009-07-28 01:57:31510 key_path.append(ShellUtil::kRegShellOpen);
[email protected]2d6503982010-10-17 04:41:54511 base::win::RegKey key(HKEY_CLASSES_ROOT, key_path.c_str(), KEY_READ);
[email protected]b6b72222012-02-11 02:04:13512 string16 app_cmd;
[email protected]e06f4d52011-01-19 07:28:46513 if (key.Valid() && (key.ReadValue(L"", &app_cmd) == ERROR_SUCCESS) &&
[email protected]b6b72222012-02-11 02:04:13514 string16::npos != StringToLowerASCII(app_cmd).find(L"firefox"))
[email protected]d24c4012009-07-28 01:57:31515 ff_default = true;
516 }
517 return ff_default;
518}
[email protected]12f520c2010-01-06 18:11:15519
[email protected]a0448002012-06-19 04:32:10520string16 ShellIntegration::GetAppModelIdForProfile(
521 const string16& app_name,
522 const FilePath& profile_path) {
523 std::vector<string16> components;
524 components.push_back(app_name);
525 const string16 profile_id(GetProfileIdFromPath(profile_path));
526 if (!profile_id.empty())
527 components.push_back(profile_id);
528 return ShellUtil::BuildAppModelId(components);
[email protected]12f520c2010-01-06 18:11:15529}
530
[email protected]a0448002012-06-19 04:32:10531string16 ShellIntegration::GetChromiumModelIdForProfile(
532 const FilePath& profile_path) {
533 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
534 FilePath chrome_exe;
535 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
536 NOTREACHED();
537 return dist->GetBaseAppId();
538 }
539 return GetAppModelIdForProfile(
540 ShellUtil::GetBrowserModelId(dist, chrome_exe.value()), profile_path);
[email protected]12f520c2010-01-06 18:11:15541}
[email protected]c9bb06f42010-01-13 23:53:48542
[email protected]2de2d622011-10-21 22:07:37543string16 ShellIntegration::GetChromiumIconPath() {
544 // Determine the app path. If we can't determine what that is, we have
545 // bigger fish to fry...
546 FilePath app_path;
547 if (!PathService::Get(base::FILE_EXE, &app_path)) {
548 NOTREACHED();
549 return string16();
550 }
551
552 string16 icon_path(app_path.value());
553 icon_path.push_back(',');
554 icon_path += base::IntToString16(
555 BrowserDistribution::GetDistribution()->GetIconIndex());
556 return icon_path;
557}
558
[email protected]c9bb06f42010-01-13 23:53:48559void ShellIntegration::MigrateChromiumShortcuts() {
[email protected]935aa542010-10-15 01:59:15560 if (base::win::GetVersion() < base::win::VERSION_WIN7)
[email protected]c9bb06f42010-01-13 23:53:48561 return;
562
[email protected]0c7d74f2010-10-11 11:55:26563 BrowserThread::PostTask(
[email protected]3a3e72c2011-11-29 02:59:38564 BrowserThread::FILE, FROM_HERE,
565 base::Bind(&MigrateChromiumShortcutsCallback));
[email protected]c9bb06f42010-01-13 23:53:48566}
[email protected]43903b82012-06-01 05:26:23567
[email protected]3f69d6e612012-08-03 18:52:27568FilePath ShellIntegration::GetStartMenuShortcut(const FilePath& chrome_exe) {
569 static const int kFolderIds[] = {
570 base::DIR_COMMON_START_MENU,
571 base::DIR_START_MENU,
572 };
573 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
574 string16 shortcut_name(dist->GetAppShortCutName());
575 FilePath shortcut;
576
577 // Check both the common and the per-user Start Menu folders for system-level
578 // installs.
579 size_t folder =
580 InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()) ? 1 : 0;
581 for (; folder < arraysize(kFolderIds); ++folder) {
582 if (!PathService::Get(kFolderIds[folder], &shortcut)) {
583 NOTREACHED();
584 continue;
585 }
586
587 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name + L".lnk");
588 if (file_util::PathExists(shortcut))
589 return shortcut;
590 }
591
592 return FilePath();
593}