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

Side by Side Diff: chrome/installer/util/shell_util.cc

Issue 1472273003: shell_util: Move RegistryEntry methods out-of-line. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
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 // 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 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 }; 214 };
215 215
216 // Returns the Windows browser client registration key for Chrome. For 216 // Returns the Windows browser client registration key for Chrome. For
217 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly 217 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly
218 // speaking, we should use the name of the executable (e.g., "chrome.exe"), 218 // speaking, we should use the name of the executable (e.g., "chrome.exe"),
219 // but that ship has sailed. The cost of switching now is re-prompting users 219 // but that ship has sailed. The cost of switching now is re-prompting users
220 // to make Chrome their default browser, which isn't polite. |suffix| is the 220 // to make Chrome their default browser, which isn't polite. |suffix| is the
221 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix 221 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix
222 // in shell_util.h for details. 222 // in shell_util.h for details.
223 static base::string16 GetBrowserClientKey(BrowserDistribution* dist, 223 static base::string16 GetBrowserClientKey(BrowserDistribution* dist,
224 const base::string16& suffix) { 224 const base::string16& suffix);
225 DCHECK(suffix.empty() || suffix[0] == L'.');
226 return base::string16(ShellUtil::kRegStartMenuInternet)
227 .append(1, L'\\')
228 .append(dist->GetBaseAppName())
229 .append(suffix);
230 }
231 225
232 // Returns the Windows Default Programs capabilities key for Chrome. For 226 // Returns the Windows Default Programs capabilities key for Chrome. For
233 // example: 227 // example:
234 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". 228 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities".
235 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, 229 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist,
236 const base::string16& suffix) { 230 const base::string16& suffix);
237 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities");
238 }
239 231
240 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is 232 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is
241 // only needed for registring a web browser, not for general associations. 233 // only needed for registring a web browser, not for general associations.
242 static ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries( 234 static ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries(
243 const base::FilePath& chrome_exe, 235 const base::FilePath& chrome_exe,
244 const ApplicationInfo& app_info) { 236 const ApplicationInfo& app_info);
245 ScopedVector<RegistryEntry> entries;
246
247 base::string16 app_id_shell_key(ShellUtil::kRegClasses);
248 app_id_shell_key.push_back(base::FilePath::kSeparators[0]);
249 app_id_shell_key.append(app_info.app_id);
250 app_id_shell_key.append(ShellUtil::kRegExePath);
251 app_id_shell_key.append(ShellUtil::kRegShellPath);
252
253 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
254 entries.push_back(
255 new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen));
256
257 // The command to execute when opening this application via the Metro UI.
258 const base::string16 delegate_command(
259 ShellUtil::GetChromeDelegateCommand(chrome_exe));
260
261 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is
262 // registered to handle some verbs. This registration has the side-effect
263 // that these verbs now show up in the shortcut's context menu. We
264 // mitigate this side-effect by making the context menu entries
265 // user readable/localized strings. See relevant MSDN article:
266 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
267 static const struct {
268 const wchar_t* verb;
269 int name_id;
270 } verbs[] = {
271 {ShellUtil::kRegVerbOpen, -1},
272 {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE},
273 };
274 for (const auto& verb_and_id : verbs) {
275 base::string16 sub_path(app_id_shell_key);
276 sub_path.push_back(base::FilePath::kSeparators[0]);
277 sub_path.append(verb_and_id.verb);
278
279 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
280 if (verb_and_id.name_id != -1) {
281 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
282 // resource.
283 const base::string16 verb_name(
284 installer::GetLocalizedString(verb_and_id.name_id));
285 entries.push_back(new RegistryEntry(sub_path, verb_name.c_str()));
286 }
287 entries.push_back(
288 new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch"));
289
290 sub_path.push_back(base::FilePath::kSeparators[0]);
291 sub_path.append(ShellUtil::kRegCommand);
292
293 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
294 entries.push_back(new RegistryEntry(sub_path, delegate_command));
295 entries.push_back(new RegistryEntry(
296 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
297 }
298
299 return entries.Pass();
300 }
301 237
302 // This method returns a list of all the registry entries that 238 // This method returns a list of all the registry entries that
303 // are needed to register this installation's ProgId and AppId. 239 // are needed to register this installation's ProgId and AppId.
304 // These entries need to be registered in HKLM prior to Win8. 240 // These entries need to be registered in HKLM prior to Win8.
305 static void GetChromeProgIdEntries(BrowserDistribution* dist, 241 static void GetChromeProgIdEntries(BrowserDistribution* dist,
306 const base::FilePath& chrome_exe, 242 const base::FilePath& chrome_exe,
307 const base::string16& suffix, 243 const base::string16& suffix,
308 ScopedVector<RegistryEntry>* entries) { 244 ScopedVector<RegistryEntry>* entries);
309 int chrome_icon_index =
310 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
311
312 ApplicationInfo app_info;
313 app_info.prog_id = GetBrowserProgId(suffix);
314 app_info.file_type_name = dist->GetBrowserProgIdDesc();
315 // File types associated with Chrome are just given the Chrome icon.
316 app_info.file_type_icon_path = chrome_exe;
317 app_info.file_type_icon_index = chrome_icon_index;
318 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
319 // For user-level installs: entries for the app id will be in HKCU; thus we
320 // do not need a suffix on those entries.
321 app_info.app_id = ShellUtil::GetBrowserModelId(
322 dist, InstallUtil::IsPerUserInstall(chrome_exe));
323
324 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
325 // resource for name, description, and company.
326 app_info.application_name = dist->GetDisplayName();
327 app_info.application_icon_path = chrome_exe;
328 app_info.application_icon_index = chrome_icon_index;
329 app_info.application_description = dist->GetAppDescription();
330 app_info.publisher_name = dist->GetPublisherName();
331
332 app_info.delegate_clsid = dist->GetCommandExecuteImplClsid();
333
334 GetProgIdEntries(app_info, entries);
335
336 if (!app_info.delegate_clsid.empty()) {
337 ScopedVector<RegistryEntry> delegate_execute_entries =
338 GetChromeDelegateExecuteEntries(chrome_exe, app_info);
339 if (!base::win::IsChromeMetroSupported()) {
340 // Remove the keys (not only their values) so that Windows will continue
341 // to launch Chrome without a pesky association error.
342 for (RegistryEntry* entry : delegate_execute_entries)
343 entry->set_removal_flag(RemovalFlag::KEY);
344 }
345 // Move |delegate_execute_entries| to |entries|.
346 entries->insert(entries->end(), delegate_execute_entries.begin(),
347 delegate_execute_entries.end());
348 delegate_execute_entries.weak_clear();
349 }
350 }
351 245
352 // Gets the registry entries to register an application in the Windows 246 // Gets the registry entries to register an application in the Windows
353 // registry. |app_info| provides all of the information needed. 247 // registry. |app_info| provides all of the information needed.
354 static void GetProgIdEntries(const ApplicationInfo& app_info, 248 static void GetProgIdEntries(const ApplicationInfo& app_info,
355 ScopedVector<RegistryEntry>* entries) { 249 ScopedVector<RegistryEntry>* entries);
356 // Basic sanity checks.
357 DCHECK(!app_info.prog_id.empty());
358 DCHECK_NE(L'.', app_info.prog_id[0]);
359
360 // File association ProgId
361 base::string16 prog_id_path(ShellUtil::kRegClasses);
362 prog_id_path.push_back(base::FilePath::kSeparators[0]);
363 prog_id_path.append(app_info.prog_id);
364 entries->push_back(
365 new RegistryEntry(prog_id_path, app_info.file_type_name));
366 entries->push_back(new RegistryEntry(
367 prog_id_path + ShellUtil::kRegDefaultIcon,
368 ShellUtil::FormatIconLocation(app_info.file_type_icon_path,
369 app_info.file_type_icon_index)));
370 entries->push_back(new RegistryEntry(
371 prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line));
372 if (!app_info.delegate_clsid.empty()) {
373 entries->push_back(
374 new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen,
375 ShellUtil::kRegDelegateExecute,
376 app_info.delegate_clsid));
377 // If Metro is not supported, remove the DelegateExecute entry instead of
378 // adding it.
379 if (!base::win::IsChromeMetroSupported())
380 entries->back()->set_removal_flag(RemovalFlag::VALUE);
381 }
382
383 // The following entries are required as of Windows 8, but do not
384 // depend on the DelegateExecute verb handler being set.
385 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
386 if (!app_info.app_id.empty()) {
387 entries->push_back(new RegistryEntry(
388 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
389 }
390
391 // Add \Software\Classes\<prog_id>\Application entries
392 base::string16 application_path(prog_id_path +
393 ShellUtil::kRegApplication);
394 if (!app_info.app_id.empty()) {
395 entries->push_back(new RegistryEntry(
396 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
397 }
398 if (!app_info.application_icon_path.empty()) {
399 entries->push_back(new RegistryEntry(
400 application_path,
401 ShellUtil::kRegApplicationIcon,
402 ShellUtil::FormatIconLocation(app_info.application_icon_path,
403 app_info.application_icon_index)));
404 }
405 if (!app_info.application_name.empty()) {
406 entries->push_back(new RegistryEntry(application_path,
407 ShellUtil::kRegApplicationName,
408 app_info.application_name));
409 }
410 if (!app_info.application_description.empty()) {
411 entries->push_back(
412 new RegistryEntry(application_path,
413 ShellUtil::kRegApplicationDescription,
414 app_info.application_description));
415 }
416 if (!app_info.publisher_name.empty()) {
417 entries->push_back(new RegistryEntry(application_path,
418 ShellUtil::kRegApplicationCompany,
419 app_info.publisher_name));
420 }
421 }
422 }
423 250
424 // This method returns a list of the registry entries needed to declare a 251 // This method returns a list of the registry entries needed to declare a
425 // capability of handling a protocol on Windows. 252 // capability of handling a protocol on Windows.
426 static void GetProtocolCapabilityEntries( 253 static void GetProtocolCapabilityEntries(
427 BrowserDistribution* dist, 254 BrowserDistribution* dist,
428 const base::string16& suffix, 255 const base::string16& suffix,
429 const base::string16& protocol, 256 const base::string16& protocol,
430 ScopedVector<RegistryEntry>* entries) { 257 ScopedVector<RegistryEntry>* entries);
431 entries->push_back(new RegistryEntry(
432 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"),
433 protocol, GetBrowserProgId(suffix)));
434 }
435 258
436 // This method returns a list of the registry entries required to register 259 // This method returns a list of the registry entries required to register
437 // this installation in "RegisteredApplications" on Windows (to appear in 260 // this installation in "RegisteredApplications" on Windows (to appear in
438 // Default Programs, StartMenuInternet, etc.). 261 // Default Programs, StartMenuInternet, etc.).
439 // These entries need to be registered in HKLM prior to Win8. 262 // These entries need to be registered in HKLM prior to Win8.
440 // If |suffix| is not empty, these entries are guaranteed to be unique on this 263 // If |suffix| is not empty, these entries are guaranteed to be unique on this
441 // machine. 264 // machine.
442 static void GetShellIntegrationEntries(BrowserDistribution* dist, 265 static void GetShellIntegrationEntries(BrowserDistribution* dist,
443 const base::FilePath& chrome_exe, 266 const base::FilePath& chrome_exe,
444 const base::string16& suffix, 267 const base::string16& suffix,
445 ScopedVector<RegistryEntry>* entries) { 268 ScopedVector<RegistryEntry>* entries);
446 const base::string16 icon_path(
447 ShellUtil::FormatIconLocation(
448 chrome_exe,
449 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
450 const base::string16 quoted_exe_path(L"\"" + chrome_exe.value() + L"\"");
451
452 // Register for the Start Menu "Internet" link (pre-Win7).
453 const base::string16 start_menu_entry(GetBrowserClientKey(dist, suffix));
454 // Register Chrome's display name.
455 // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
456 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85) .aspx#registering_the_display_name
457 entries->push_back(new RegistryEntry(
458 start_menu_entry, dist->GetDisplayName()));
459 // Register the "open" verb for launching Chrome via the "Internet" link.
460 entries->push_back(new RegistryEntry(
461 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
462 // Register Chrome's icon for the Start Menu "Internet" link.
463 entries->push_back(new RegistryEntry(
464 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path));
465
466 // Register installation information.
467 base::string16 install_info(start_menu_entry + L"\\InstallInfo");
468 // Note: not using CommandLine since it has ambiguous rules for quoting
469 // strings.
470 entries->push_back(new RegistryEntry(install_info, kReinstallCommand,
471 quoted_exe_path + L" --" +
472 base::ASCIIToUTF16(switches::kMakeDefaultBrowser)));
473 entries->push_back(new RegistryEntry(install_info, L"HideIconsCommand",
474 quoted_exe_path + L" --" +
475 base::ASCIIToUTF16(switches::kHideIcons)));
476 entries->push_back(new RegistryEntry(install_info, L"ShowIconsCommand",
477 quoted_exe_path + L" --" +
478 base::ASCIIToUTF16(switches::kShowIcons)));
479 entries->push_back(new RegistryEntry(install_info, L"IconsVisible", 1));
480
481 // Register with Default Programs.
482 const base::string16 reg_app_name(dist->GetBaseAppName().append(suffix));
483 // Tell Windows where to find Chrome's Default Programs info.
484 const base::string16 capabilities(GetCapabilitiesKey(dist, suffix));
485 entries->push_back(new RegistryEntry(ShellUtil::kRegRegisteredApplications,
486 reg_app_name, capabilities));
487 // Write out Chrome's Default Programs info.
488 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
489 // resource rather than this.
490 entries->push_back(new RegistryEntry(
491 capabilities, ShellUtil::kRegApplicationDescription,
492 dist->GetLongAppDescription()));
493 entries->push_back(new RegistryEntry(
494 capabilities, ShellUtil::kRegApplicationIcon, icon_path));
495 entries->push_back(new RegistryEntry(
496 capabilities, ShellUtil::kRegApplicationName,
497 dist->GetDisplayName()));
498
499 entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu",
500 L"StartMenuInternet", reg_app_name));
501
502 const base::string16 html_prog_id(GetBrowserProgId(suffix));
503 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
504 entries->push_back(new RegistryEntry(
505 capabilities + L"\\FileAssociations",
506 ShellUtil::kPotentialFileAssociations[i], html_prog_id));
507 }
508 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL;
509 i++) {
510 entries->push_back(new RegistryEntry(
511 capabilities + L"\\URLAssociations",
512 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id));
513 }
514 }
515 269
516 // This method returns a list of the registry entries required for this 270 // This method returns a list of the registry entries required for this
517 // installation to be registered in the Windows shell. 271 // installation to be registered in the Windows shell.
518 // In particular: 272 // In particular:
519 // - App Paths 273 // - App Paths
520 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121 274 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
521 // - File Associations 275 // - File Associations
522 // http://msdn.microsoft.com/en-us/library/bb166549 276 // http://msdn.microsoft.com/en-us/library/bb166549
523 // These entries need to be registered in HKLM prior to Win8. 277 // These entries need to be registered in HKLM prior to Win8.
524 static void GetChromeAppRegistrationEntries( 278 static void GetChromeAppRegistrationEntries(
525 const base::FilePath& chrome_exe, 279 const base::FilePath& chrome_exe,
526 const base::string16& suffix, 280 const base::string16& suffix,
527 ScopedVector<RegistryEntry>* entries) { 281 ScopedVector<RegistryEntry>* entries);
528 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
529 app_path_key.push_back(base::FilePath::kSeparators[0]);
530 app_path_key.append(chrome_exe.BaseName().value());
531 entries->push_back(new RegistryEntry(app_path_key, chrome_exe.value()));
532 entries->push_back(new RegistryEntry(app_path_key,
533 ShellUtil::kAppPathsRegistryPathName,
534 chrome_exe.DirName().value()));
535
536 const base::string16 html_prog_id(GetBrowserProgId(suffix));
537 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
538 GetAppExtRegistrationEntries(
539 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries);
540 }
541 }
542 282
543 // Gets the registry entries to register an application as a handler for a 283 // Gets the registry entries to register an application as a handler for a
544 // particular file extension. |prog_id| is the ProgId used by Windows for the 284 // particular file extension. |prog_id| is the ProgId used by Windows for the
545 // application. |ext| is the file extension, which must begin with a '.'. 285 // application. |ext| is the file extension, which must begin with a '.'.
546 static void GetAppExtRegistrationEntries( 286 static void GetAppExtRegistrationEntries(
547 const base::string16& prog_id, 287 const base::string16& prog_id,
548 const base::string16& ext, 288 const base::string16& ext,
549 ScopedVector<RegistryEntry>* entries) { 289 ScopedVector<RegistryEntry>* entries);
550 // In HKEY_CURRENT_USER\Software\Classes\EXT\OpenWithProgids, create an
551 // empty value with this class's ProgId.
552 base::string16 key_name(ShellUtil::kRegClasses);
553 key_name.push_back(base::FilePath::kSeparators[0]);
554 key_name.append(ext);
555 key_name.push_back(base::FilePath::kSeparators[0]);
556 key_name.append(ShellUtil::kRegOpenWithProgids);
557 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16()));
558 }
559 290
560 // Gets the registry entries to register an application as the default handler 291 // Gets the registry entries to register an application as the default handler
561 // for a particular file extension. |prog_id| is the ProgId used by Windows 292 // for a particular file extension. |prog_id| is the ProgId used by Windows
562 // for the application. |ext| is the file extension, which must begin with a 293 // for the application. |ext| is the file extension, which must begin with a
563 // '.'. If |overwrite_existing|, always sets the default handler; otherwise 294 // '.'. If |overwrite_existing|, always sets the default handler; otherwise
564 // only sets if there is no existing default. 295 // only sets if there is no existing default.
565 // 296 //
566 // This has no effect on Windows 8. Windows 8 ignores the default and lets the 297 // This has no effect on Windows 8. Windows 8 ignores the default and lets the
567 // user choose. If there is only one handler for a file, it will automatically 298 // user choose. If there is only one handler for a file, it will automatically
568 // become the default. Otherwise, the first time the user opens a file, they 299 // become the default. Otherwise, the first time the user opens a file, they
569 // are presented with the dialog to set the default handler. (This is roughly 300 // are presented with the dialog to set the default handler. (This is roughly
570 // equivalent to being called with |overwrite_existing| false.) 301 // equivalent to being called with |overwrite_existing| false.)
571 static void GetAppDefaultRegistrationEntries( 302 static void GetAppDefaultRegistrationEntries(
572 const base::string16& prog_id, 303 const base::string16& prog_id,
573 const base::string16& ext, 304 const base::string16& ext,
574 bool overwrite_existing, 305 bool overwrite_existing,
575 ScopedVector<RegistryEntry>* entries) { 306 ScopedVector<RegistryEntry>* entries);
576 // Set the default value of HKEY_CURRENT_USER\Software\Classes\EXT to this
577 // class's name.
578 base::string16 key_name(ShellUtil::kRegClasses);
579 key_name.push_back(base::FilePath::kSeparators[0]);
580 key_name.append(ext);
581 scoped_ptr<RegistryEntry> default_association(
582 new RegistryEntry(key_name, prog_id));
583 if (overwrite_existing ||
584 !default_association->KeyExistsInRegistry(
585 RegistryEntry::LOOK_IN_HKCU)) {
586 entries->push_back(default_association.release());
587 }
588 }
589 307
590 // This method returns a list of all the user level registry entries that 308 // This method returns a list of all the user level registry entries that
591 // are needed to make Chromium the default handler for a protocol on XP. 309 // are needed to make Chromium the default handler for a protocol on XP.
592 static void GetXPStyleUserProtocolEntries( 310 static void GetXPStyleUserProtocolEntries(
593 const base::string16& protocol, 311 const base::string16& protocol,
594 const base::string16& chrome_icon, 312 const base::string16& chrome_icon,
595 const base::string16& chrome_open, 313 const base::string16& chrome_open,
596 ScopedVector<RegistryEntry>* entries) { 314 ScopedVector<RegistryEntry>* entries);
597 // Protocols associations.
598 base::string16 url_key(ShellUtil::kRegClasses);
599 url_key.push_back(base::FilePath::kSeparators[0]);
600 url_key.append(protocol);
601
602 // This registry value tells Windows that this 'class' is a URL scheme
603 // so IE, explorer and other apps will route it to our handler.
604 // <root hkey>\Software\Classes\<protocol>\URL Protocol
605 entries->push_back(new RegistryEntry(url_key,
606 ShellUtil::kRegUrlProtocol, base::string16()));
607
608 // <root hkey>\Software\Classes\<protocol>\DefaultIcon
609 base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon;
610 entries->push_back(new RegistryEntry(icon_key, chrome_icon));
611
612 // <root hkey>\Software\Classes\<protocol>\shell\open\command
613 base::string16 shell_key = url_key + ShellUtil::kRegShellOpen;
614 entries->push_back(new RegistryEntry(shell_key, chrome_open));
615
616 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
617 base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec";
618 entries->push_back(new RegistryEntry(dde_key, base::string16()));
619
620 // <root hkey>\Software\Classes\<protocol>\shell\@
621 base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath;
622 entries->push_back(new RegistryEntry(protocol_shell_key, L"open"));
623 }
624 315
625 // This method returns a list of all the user level registry entries that 316 // This method returns a list of all the user level registry entries that
626 // are needed to make Chromium default browser on XP. 317 // are needed to make Chromium default browser on XP.
627 // Some of these entries are irrelevant in recent versions of Windows, but 318 // Some of these entries are irrelevant in recent versions of Windows, but
628 // we register them anyways as some legacy apps are hardcoded to lookup those 319 // we register them anyways as some legacy apps are hardcoded to lookup those
629 // values. 320 // values.
630 static void GetXPStyleDefaultBrowserUserEntries( 321 static void GetXPStyleDefaultBrowserUserEntries(
631 BrowserDistribution* dist, 322 BrowserDistribution* dist,
632 const base::FilePath& chrome_exe, 323 const base::FilePath& chrome_exe,
633 const base::string16& suffix, 324 const base::string16& suffix,
634 ScopedVector<RegistryEntry>* entries) { 325 ScopedVector<RegistryEntry>* entries);
635 // File extension associations.
636 base::string16 html_prog_id(GetBrowserProgId(suffix));
637 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
638 GetAppDefaultRegistrationEntries(
639 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries);
640 }
641
642 // Protocols associations.
643 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
644 base::string16 chrome_icon =
645 ShellUtil::FormatIconLocation(
646 chrome_exe,
647 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
648 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
649 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i],
650 chrome_icon, chrome_open, entries);
651 }
652
653 // start->Internet shortcut.
654 base::string16 start_menu(ShellUtil::kRegStartMenuInternet);
655 base::string16 app_name = dist->GetBaseAppName() + suffix;
656 entries->push_back(new RegistryEntry(start_menu, app_name));
657 }
658 326
659 // Flags this RegistryKey with |removal_flag|, indicating that it should be 327 // Flags this RegistryKey with |removal_flag|, indicating that it should be
660 // removed rather than created. Note that this will not result in cleaning up 328 // removed rather than created. Note that this will not result in cleaning up
661 // the entire registry hierarchy below RegistryEntry even if it is left empty 329 // the entire registry hierarchy below RegistryEntry even if it is left empty
662 // by this operation (this should thus not be used for uninstall, but only to 330 // by this operation (this should thus not be used for uninstall, but only to
663 // unregister keys that should explicitly no longer be active in the current 331 // unregister keys that should explicitly no longer be active in the current
664 // configuration). 332 // configuration).
665 void set_removal_flag(RemovalFlag removal_flag) { 333 void set_removal_flag(RemovalFlag removal_flag) {
666 removal_flag_ = removal_flag; 334 removal_flag_ = removal_flag;
667 } 335 }
668 336
669 // Generates work_item tasks required to create (or potentially delete based 337 // Generates work_item tasks required to create (or potentially delete based
670 // on |removal_flag_|) the current RegistryEntry and add them to the given 338 // on |removal_flag_|) the current RegistryEntry and add them to the given
671 // work item list. 339 // work item list.
672 void AddToWorkItemList(HKEY root, WorkItemList *items) const { 340 void AddToWorkItemList(HKEY root, WorkItemList* items) const;
673 if (removal_flag_ == RemovalFlag::VALUE) {
674 items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
675 name_);
676 } else if (removal_flag_ == RemovalFlag::KEY) {
677 items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
678 } else {
679 DCHECK(removal_flag_ == RemovalFlag::NONE);
680 items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
681 if (is_string_) {
682 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
683 name_, value_, true);
684 } else {
685 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
686 name_, int_value_, true);
687 }
688 }
689 }
690 341
691 // Returns true if this key is flagged for removal. 342 // Returns true if this key is flagged for removal.
692 bool IsFlaggedForRemoval() const { 343 bool IsFlaggedForRemoval() const {
693 return removal_flag_ != RemovalFlag::NONE; 344 return removal_flag_ != RemovalFlag::NONE;
694 } 345 }
695 346
696 // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| 347 // Checks if the current registry entry exists in HKCU\|key_path_|\|name_|
697 // and value is |value_|. If the key does NOT exist in HKCU, checks for 348 // and value is |value_|. If the key does NOT exist in HKCU, checks for
698 // the correct name and value in HKLM. 349 // the correct name and value in HKLM.
699 // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the 350 // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the
700 // key, unspecified roots are not looked into (i.e. the the key is assumed not 351 // key, unspecified roots are not looked into (i.e. the the key is assumed not
701 // to exist in them). 352 // to exist in them).
702 // |look_for_in| must at least specify one root to look into. 353 // |look_for_in| must at least specify one root to look into.
703 // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' 354 // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows'
704 // behavior when searching in HKCR (HKCU takes precedence over HKLM). For 355 // behavior when searching in HKCR (HKCU takes precedence over HKLM). For
705 // registrations outside of HKCR on versions of Windows prior to Win8, 356 // registrations outside of HKCR on versions of Windows prior to Win8,
706 // Chrome's values go in HKLM. This function will make unnecessary (but 357 // Chrome's values go in HKLM. This function will make unnecessary (but
707 // harmless) queries into HKCU in that case. 358 // harmless) queries into HKCU in that case.
708 bool ExistsInRegistry(uint32 look_for_in) const { 359 bool ExistsInRegistry(uint32 look_for_in) const;
709 DCHECK(look_for_in);
710
711 RegistryStatus status = DOES_NOT_EXIST;
712 if (look_for_in & LOOK_IN_HKCU)
713 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
714 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
715 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
716 return status == SAME_VALUE;
717 }
718 360
719 // Checks if the current registry entry exists in \|key_path_|\|name_|, 361 // Checks if the current registry entry exists in \|key_path_|\|name_|,
720 // regardless of value. Same lookup rules as ExistsInRegistry. 362 // regardless of value. Same lookup rules as ExistsInRegistry.
721 // Unlike ExistsInRegistry, this returns true if some other value is present 363 // Unlike ExistsInRegistry, this returns true if some other value is present
722 // with the same key. 364 // with the same key.
723 bool KeyExistsInRegistry(uint32 look_for_in) const { 365 bool KeyExistsInRegistry(uint32 look_for_in) const;
724 DCHECK(look_for_in);
725
726 RegistryStatus status = DOES_NOT_EXIST;
727 if (look_for_in & LOOK_IN_HKCU)
728 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
729 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
730 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
731 return status != DOES_NOT_EXIST;
732 }
733 366
734 private: 367 private:
735 // States this RegistryKey can be in compared to the registry. 368 // States this RegistryKey can be in compared to the registry.
736 enum RegistryStatus { 369 enum RegistryStatus {
737 // |name_| does not exist in the registry 370 // |name_| does not exist in the registry
738 DOES_NOT_EXIST, 371 DOES_NOT_EXIST,
739 // |name_| exists, but its value != |value_| 372 // |name_| exists, but its value != |value_|
740 DIFFERENT_VALUE, 373 DIFFERENT_VALUE,
741 // |name_| exists and its value is |value_| 374 // |name_| exists and its value is |value_|
742 SAME_VALUE, 375 SAME_VALUE,
743 }; 376 };
744 377
745 // Create a object that represent default value of a key 378 // Create a object that represent default value of a key
746 RegistryEntry(const base::string16& key_path, const base::string16& value) 379 RegistryEntry(const base::string16& key_path, const base::string16& value);
747 : key_path_(key_path),
748 name_(),
749 is_string_(true),
750 value_(value),
751 int_value_(0),
752 removal_flag_(RemovalFlag::NONE) {}
753 380
754 // Create a object that represent a key of type REG_SZ 381 // Create a object that represent a key of type REG_SZ
755 RegistryEntry(const base::string16& key_path, 382 RegistryEntry(const base::string16& key_path,
756 const base::string16& name, 383 const base::string16& name,
757 const base::string16& value) 384 const base::string16& value);
758 : key_path_(key_path),
759 name_(name),
760 is_string_(true),
761 value_(value),
762 int_value_(0),
763 removal_flag_(RemovalFlag::NONE) {}
764 385
765 // Create a object that represent a key of integer type 386 // Create a object that represent a key of integer type
766 RegistryEntry(const base::string16& key_path, 387 RegistryEntry(const base::string16& key_path,
767 const base::string16& name, 388 const base::string16& name,
768 DWORD value) 389 DWORD value);
769 : key_path_(key_path),
770 name_(name),
771 is_string_(false),
772 value_(),
773 int_value_(value),
774 removal_flag_(RemovalFlag::NONE) {}
775 390
776 base::string16 key_path_; // key path for the registry entry 391 base::string16 key_path_; // key path for the registry entry
777 base::string16 name_; // name of the registry entry 392 base::string16 name_; // name of the registry entry
778 bool is_string_; // true if current registry entry is of type REG_SZ 393 bool is_string_; // true if current registry entry is of type REG_SZ
779 base::string16 value_; // string value (useful if is_string_ = true) 394 base::string16 value_; // string value (useful if is_string_ = true)
780 DWORD int_value_; // integer value (useful if is_string_ = false) 395 DWORD int_value_; // integer value (useful if is_string_ = false)
781 396
782 // Identifies whether this RegistryEntry is flagged for removal (i.e. no 397 // Identifies whether this RegistryEntry is flagged for removal (i.e. no
783 // longer relevant on the configuration it was created under). 398 // longer relevant on the configuration it was created under).
784 RemovalFlag removal_flag_; 399 RemovalFlag removal_flag_;
785 400
786 // Helper function for ExistsInRegistry(). 401 // Helper function for ExistsInRegistry().
787 // Returns the RegistryStatus of the current registry entry in 402 // Returns the RegistryStatus of the current registry entry in
788 // |root|\|key_path_|\|name_|. 403 // |root|\|key_path_|\|name_|.
789 RegistryStatus StatusInRegistryUnderRoot(HKEY root) const { 404 RegistryStatus StatusInRegistryUnderRoot(HKEY root) const;
790 RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE);
791 bool found = false;
792 bool correct_value = false;
793 if (is_string_) {
794 base::string16 read_value;
795 found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS;
796 if (found) {
797 correct_value = read_value.size() == value_.size() &&
798 ::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
799 read_value.data(),
800 base::saturated_cast<int>(read_value.size()),
801 value_.data(),
802 base::saturated_cast<int>(value_.size()))
803 == CSTR_EQUAL;
804 }
805 } else {
806 DWORD read_value;
807 found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS;
808 if (found)
809 correct_value = read_value == int_value_;
810 }
811 return found ?
812 (correct_value ? SAME_VALUE : DIFFERENT_VALUE) : DOES_NOT_EXIST;
813 }
814 405
815 DISALLOW_COPY_AND_ASSIGN(RegistryEntry); 406 DISALLOW_COPY_AND_ASSIGN(RegistryEntry);
816 }; // class RegistryEntry 407 }; // class RegistryEntry
817 408
409 // static
410 base::string16 RegistryEntry::GetBrowserClientKey(
411 BrowserDistribution* dist,
412 const base::string16& suffix) {
413 DCHECK(suffix.empty() || suffix[0] == L'.');
414 return base::string16(ShellUtil::kRegStartMenuInternet)
415 .append(1, L'\\')
416 .append(dist->GetBaseAppName())
417 .append(suffix);
418 }
419
420 // static
421 base::string16 RegistryEntry::GetCapabilitiesKey(BrowserDistribution* dist,
422 const base::string16& suffix) {
423 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities");
424 }
425
426 // static
427 ScopedVector<RegistryEntry> RegistryEntry::GetChromeDelegateExecuteEntries(
428 const base::FilePath& chrome_exe,
429 const RegistryEntry::ApplicationInfo& app_info) {
430 ScopedVector<RegistryEntry> entries;
431
432 base::string16 app_id_shell_key(ShellUtil::kRegClasses);
433 app_id_shell_key.push_back(base::FilePath::kSeparators[0]);
434 app_id_shell_key.append(app_info.app_id);
435 app_id_shell_key.append(ShellUtil::kRegExePath);
436 app_id_shell_key.append(ShellUtil::kRegShellPath);
437
438 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
439 entries.push_back(
440 new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen));
441
442 // The command to execute when opening this application via the Metro UI.
443 const base::string16 delegate_command(
444 ShellUtil::GetChromeDelegateCommand(chrome_exe));
445
446 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is
447 // registered to handle some verbs. This registration has the side-effect
448 // that these verbs now show up in the shortcut's context menu. We
449 // mitigate this side-effect by making the context menu entries
450 // user readable/localized strings. See relevant MSDN article:
451 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
452 static const struct {
453 const wchar_t* verb;
454 int name_id;
455 } verbs[] = {
456 {ShellUtil::kRegVerbOpen, -1},
457 {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE},
458 };
459 for (const auto& verb_and_id : verbs) {
460 base::string16 sub_path(app_id_shell_key);
461 sub_path.push_back(base::FilePath::kSeparators[0]);
462 sub_path.append(verb_and_id.verb);
463
464 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
465 if (verb_and_id.name_id != -1) {
466 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
467 // resource.
468 const base::string16 verb_name(
469 installer::GetLocalizedString(verb_and_id.name_id));
470 entries.push_back(new RegistryEntry(sub_path, verb_name.c_str()));
471 }
472 entries.push_back(
473 new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch"));
474
475 sub_path.push_back(base::FilePath::kSeparators[0]);
476 sub_path.append(ShellUtil::kRegCommand);
477
478 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
479 entries.push_back(new RegistryEntry(sub_path, delegate_command));
480 entries.push_back(new RegistryEntry(
481 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
482 }
483
484 return entries.Pass();
485 }
486
487 // static
488 void RegistryEntry::GetChromeProgIdEntries(
489 BrowserDistribution* dist,
490 const base::FilePath& chrome_exe,
491 const base::string16& suffix,
492 ScopedVector<RegistryEntry>* entries) {
493 int chrome_icon_index =
494 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
495
496 ApplicationInfo app_info;
497 app_info.prog_id = GetBrowserProgId(suffix);
498 app_info.file_type_name = dist->GetBrowserProgIdDesc();
499 // File types associated with Chrome are just given the Chrome icon.
500 app_info.file_type_icon_path = chrome_exe;
501 app_info.file_type_icon_index = chrome_icon_index;
502 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
503 // For user-level installs: entries for the app id will be in HKCU; thus we
504 // do not need a suffix on those entries.
505 app_info.app_id = ShellUtil::GetBrowserModelId(
506 dist, InstallUtil::IsPerUserInstall(chrome_exe));
507
508 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
509 // resource for name, description, and company.
510 app_info.application_name = dist->GetDisplayName();
511 app_info.application_icon_path = chrome_exe;
512 app_info.application_icon_index = chrome_icon_index;
513 app_info.application_description = dist->GetAppDescription();
514 app_info.publisher_name = dist->GetPublisherName();
515
516 app_info.delegate_clsid = dist->GetCommandExecuteImplClsid();
517
518 GetProgIdEntries(app_info, entries);
519
520 if (!app_info.delegate_clsid.empty()) {
521 ScopedVector<RegistryEntry> delegate_execute_entries =
522 GetChromeDelegateExecuteEntries(chrome_exe, app_info);
523 if (!base::win::IsChromeMetroSupported()) {
524 // Remove the keys (not only their values) so that Windows will continue
525 // to launch Chrome without a pesky association error.
526 for (RegistryEntry* entry : delegate_execute_entries)
527 entry->set_removal_flag(RemovalFlag::KEY);
528 }
529 // Move |delegate_execute_entries| to |entries|.
530 entries->insert(entries->end(), delegate_execute_entries.begin(),
531 delegate_execute_entries.end());
532 delegate_execute_entries.weak_clear();
533 }
534 }
535
536 // static
537 void RegistryEntry::GetProgIdEntries(
538 const RegistryEntry::ApplicationInfo& app_info,
539 ScopedVector<RegistryEntry>* entries) {
540 // Basic sanity checks.
541 DCHECK(!app_info.prog_id.empty());
542 DCHECK_NE(L'.', app_info.prog_id[0]);
543
544 // File association ProgId
545 base::string16 prog_id_path(ShellUtil::kRegClasses);
546 prog_id_path.push_back(base::FilePath::kSeparators[0]);
547 prog_id_path.append(app_info.prog_id);
548 entries->push_back(new RegistryEntry(prog_id_path, app_info.file_type_name));
549 entries->push_back(new RegistryEntry(
550 prog_id_path + ShellUtil::kRegDefaultIcon,
551 ShellUtil::FormatIconLocation(app_info.file_type_icon_path,
552 app_info.file_type_icon_index)));
553 entries->push_back(new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen,
554 app_info.command_line));
555 if (!app_info.delegate_clsid.empty()) {
556 entries->push_back(new RegistryEntry(
557 prog_id_path + ShellUtil::kRegShellOpen, ShellUtil::kRegDelegateExecute,
558 app_info.delegate_clsid));
559 // If Metro is not supported, remove the DelegateExecute entry instead of
560 // adding it.
561 if (!base::win::IsChromeMetroSupported())
562 entries->back()->set_removal_flag(RemovalFlag::VALUE);
563 }
564
565 // The following entries are required as of Windows 8, but do not
566 // depend on the DelegateExecute verb handler being set.
567 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
568 if (!app_info.app_id.empty()) {
569 entries->push_back(new RegistryEntry(
570 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
571 }
572
573 // Add \Software\Classes\<prog_id>\Application entries
574 base::string16 application_path(prog_id_path + ShellUtil::kRegApplication);
575 if (!app_info.app_id.empty()) {
576 entries->push_back(new RegistryEntry(
577 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
578 }
579 if (!app_info.application_icon_path.empty()) {
580 entries->push_back(new RegistryEntry(
581 application_path, ShellUtil::kRegApplicationIcon,
582 ShellUtil::FormatIconLocation(app_info.application_icon_path,
583 app_info.application_icon_index)));
584 }
585 if (!app_info.application_name.empty()) {
586 entries->push_back(new RegistryEntry(application_path,
587 ShellUtil::kRegApplicationName,
588 app_info.application_name));
589 }
590 if (!app_info.application_description.empty()) {
591 entries->push_back(new RegistryEntry(
592 application_path, ShellUtil::kRegApplicationDescription,
593 app_info.application_description));
594 }
595 if (!app_info.publisher_name.empty()) {
596 entries->push_back(new RegistryEntry(application_path,
597 ShellUtil::kRegApplicationCompany,
598 app_info.publisher_name));
599 }
600 }
601 }
602
603 // static
604 void RegistryEntry::GetProtocolCapabilityEntries(
605 BrowserDistribution* dist,
606 const base::string16& suffix,
607 const base::string16& protocol,
608 ScopedVector<RegistryEntry>* entries) {
609 entries->push_back(new RegistryEntry(
610 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), protocol,
611 GetBrowserProgId(suffix)));
612 }
613
614 // static
615 void RegistryEntry::GetShellIntegrationEntries(
616 BrowserDistribution* dist,
617 const base::FilePath& chrome_exe,
618 const base::string16& suffix,
619 ScopedVector<RegistryEntry>* entries) {
620 const base::string16 icon_path(ShellUtil::FormatIconLocation(
621 chrome_exe, dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
622 const base::string16 quoted_exe_path(L"\"" + chrome_exe.value() + L"\"");
623
624 // Register for the Start Menu "Internet" link (pre-Win7).
625 const base::string16 start_menu_entry(GetBrowserClientKey(dist, suffix));
626 // Register Chrome's display name.
627 // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
628 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).a spx#registering_the_display_name
629 entries->push_back(
630 new RegistryEntry(start_menu_entry, dist->GetDisplayName()));
631 // Register the "open" verb for launching Chrome via the "Internet" link.
632 entries->push_back(new RegistryEntry(
633 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
634 // Register Chrome's icon for the Start Menu "Internet" link.
635 entries->push_back(new RegistryEntry(
636 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path));
637
638 // Register installation information.
639 base::string16 install_info(start_menu_entry + L"\\InstallInfo");
640 // Note: not using CommandLine since it has ambiguous rules for quoting
641 // strings.
642 entries->push_back(
643 new RegistryEntry(install_info, kReinstallCommand,
644 quoted_exe_path + L" --" +
645 base::ASCIIToUTF16(switches::kMakeDefaultBrowser)));
646 entries->push_back(new RegistryEntry(
647 install_info, L"HideIconsCommand",
648 quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kHideIcons)));
649 entries->push_back(new RegistryEntry(
650 install_info, L"ShowIconsCommand",
651 quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kShowIcons)));
652 entries->push_back(new RegistryEntry(install_info, L"IconsVisible", 1));
653
654 // Register with Default Programs.
655 const base::string16 reg_app_name(dist->GetBaseAppName().append(suffix));
656 // Tell Windows where to find Chrome's Default Programs info.
657 const base::string16 capabilities(GetCapabilitiesKey(dist, suffix));
658 entries->push_back(new RegistryEntry(ShellUtil::kRegRegisteredApplications,
659 reg_app_name, capabilities));
660 // Write out Chrome's Default Programs info.
661 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
662 // resource rather than this.
663 entries->push_back(new RegistryEntry(capabilities,
664 ShellUtil::kRegApplicationDescription,
665 dist->GetLongAppDescription()));
666 entries->push_back(new RegistryEntry(
667 capabilities, ShellUtil::kRegApplicationIcon, icon_path));
668 entries->push_back(new RegistryEntry(
669 capabilities, ShellUtil::kRegApplicationName, dist->GetDisplayName()));
670
671 entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu",
672 L"StartMenuInternet", reg_app_name));
673
674 const base::string16 html_prog_id(GetBrowserProgId(suffix));
675 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
676 entries->push_back(new RegistryEntry(
677 capabilities + L"\\FileAssociations",
678 ShellUtil::kPotentialFileAssociations[i], html_prog_id));
679 }
680 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; i++) {
681 entries->push_back(new RegistryEntry(
682 capabilities + L"\\URLAssociations",
683 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id));
684 }
685 }
686
687 // static
688 void RegistryEntry::GetChromeAppRegistrationEntries(
689 const base::FilePath& chrome_exe,
690 const base::string16& suffix,
691 ScopedVector<RegistryEntry>* entries) {
692 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
693 app_path_key.push_back(base::FilePath::kSeparators[0]);
694 app_path_key.append(chrome_exe.BaseName().value());
695 entries->push_back(new RegistryEntry(app_path_key, chrome_exe.value()));
696 entries->push_back(new RegistryEntry(app_path_key,
697 ShellUtil::kAppPathsRegistryPathName,
698 chrome_exe.DirName().value()));
699
700 const base::string16 html_prog_id(GetBrowserProgId(suffix));
701 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
702 GetAppExtRegistrationEntries(
703 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries);
704 }
705 }
706
707 // static
708 void RegistryEntry::GetAppExtRegistrationEntries(
709 const base::string16& prog_id,
710 const base::string16& ext,
711 ScopedVector<RegistryEntry>* entries) {
712 // In HKEY_CURRENT_USER\Software\Classes\EXT\OpenWithProgids, create an
713 // empty value with this class's ProgId.
714 base::string16 key_name(ShellUtil::kRegClasses);
715 key_name.push_back(base::FilePath::kSeparators[0]);
716 key_name.append(ext);
717 key_name.push_back(base::FilePath::kSeparators[0]);
718 key_name.append(ShellUtil::kRegOpenWithProgids);
719 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16()));
720 }
721
722 // static
723 void RegistryEntry::GetAppDefaultRegistrationEntries(
724 const base::string16& prog_id,
725 const base::string16& ext,
726 bool overwrite_existing,
727 ScopedVector<RegistryEntry>* entries) {
728 // Set the default value of HKEY_CURRENT_USER\Software\Classes\EXT to this
729 // class's name.
730 base::string16 key_name(ShellUtil::kRegClasses);
731 key_name.push_back(base::FilePath::kSeparators[0]);
732 key_name.append(ext);
733 scoped_ptr<RegistryEntry> default_association(
734 new RegistryEntry(key_name, prog_id));
735 if (overwrite_existing ||
736 !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU)) {
737 entries->push_back(default_association.release());
738 }
739 }
740
741 // static
742 void RegistryEntry::GetXPStyleUserProtocolEntries(
743 const base::string16& protocol,
744 const base::string16& chrome_icon,
745 const base::string16& chrome_open,
746 ScopedVector<RegistryEntry>* entries) {
747 // Protocols associations.
748 base::string16 url_key(ShellUtil::kRegClasses);
749 url_key.push_back(base::FilePath::kSeparators[0]);
750 url_key.append(protocol);
751
752 // This registry value tells Windows that this 'class' is a URL scheme
753 // so IE, explorer and other apps will route it to our handler.
754 // <root hkey>\Software\Classes\<protocol>\URL Protocol
755 entries->push_back(
756 new RegistryEntry(url_key, ShellUtil::kRegUrlProtocol, base::string16()));
757
758 // <root hkey>\Software\Classes\<protocol>\DefaultIcon
759 base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon;
760 entries->push_back(new RegistryEntry(icon_key, chrome_icon));
761
762 // <root hkey>\Software\Classes\<protocol>\shell\open\command
763 base::string16 shell_key = url_key + ShellUtil::kRegShellOpen;
764 entries->push_back(new RegistryEntry(shell_key, chrome_open));
765
766 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
767 base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec";
768 entries->push_back(new RegistryEntry(dde_key, base::string16()));
769
770 // <root hkey>\Software\Classes\<protocol>\shell\@
771 base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath;
772 entries->push_back(new RegistryEntry(protocol_shell_key, L"open"));
773 }
774
775 // static
776 void RegistryEntry::GetXPStyleDefaultBrowserUserEntries(
777 BrowserDistribution* dist,
778 const base::FilePath& chrome_exe,
779 const base::string16& suffix,
780 ScopedVector<RegistryEntry>* entries) {
781 // File extension associations.
782 base::string16 html_prog_id(GetBrowserProgId(suffix));
783 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
784 GetAppDefaultRegistrationEntries(
785 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries);
786 }
787
788 // Protocols associations.
789 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
790 base::string16 chrome_icon = ShellUtil::FormatIconLocation(
791 chrome_exe, dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
792 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
793 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i],
794 chrome_icon, chrome_open, entries);
795 }
796
797 // start->Internet shortcut.
798 base::string16 start_menu(ShellUtil::kRegStartMenuInternet);
799 base::string16 app_name = dist->GetBaseAppName() + suffix;
800 entries->push_back(new RegistryEntry(start_menu, app_name));
801 }
802
803 void RegistryEntry::AddToWorkItemList(HKEY root, WorkItemList* items) const {
804 if (removal_flag_ == RemovalFlag::VALUE) {
805 items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
806 name_);
807 } else if (removal_flag_ == RemovalFlag::KEY) {
808 items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
809 } else {
810 DCHECK(removal_flag_ == RemovalFlag::NONE);
811 items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
812 if (is_string_) {
813 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
814 name_, value_, true);
815 } else {
816 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default,
817 name_, int_value_, true);
818 }
819 }
820 }
821
822 bool RegistryEntry::ExistsInRegistry(uint32 look_for_in) const {
823 DCHECK(look_for_in);
824
825 RegistryStatus status = DOES_NOT_EXIST;
826 if (look_for_in & LOOK_IN_HKCU)
827 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
828 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
829 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
830 return status == SAME_VALUE;
831 }
832
833 bool RegistryEntry::KeyExistsInRegistry(uint32 look_for_in) const {
834 DCHECK(look_for_in);
835
836 RegistryStatus status = DOES_NOT_EXIST;
837 if (look_for_in & LOOK_IN_HKCU)
838 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
839 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
840 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
841 return status != DOES_NOT_EXIST;
842 }
843
844 RegistryEntry::RegistryEntry(const base::string16& key_path,
845 const base::string16& value)
846 : key_path_(key_path),
847 name_(),
848 is_string_(true),
849 value_(value),
850 int_value_(0),
851 removal_flag_(RemovalFlag::NONE) {}
852
853 RegistryEntry::RegistryEntry(const base::string16& key_path,
854 const base::string16& name,
855 const base::string16& value)
856 : key_path_(key_path),
857 name_(name),
858 is_string_(true),
859 value_(value),
860 int_value_(0),
861 removal_flag_(RemovalFlag::NONE) {}
862
863 RegistryEntry::RegistryEntry(const base::string16& key_path,
864 const base::string16& name,
865 DWORD value)
866 : key_path_(key_path),
867 name_(name),
868 is_string_(false),
869 value_(),
870 int_value_(value),
871 removal_flag_(RemovalFlag::NONE) {}
872
873 RegistryEntry::RegistryStatus RegistryEntry::StatusInRegistryUnderRoot(
874 HKEY root) const {
875 RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE);
876 bool found = false;
877 bool correct_value = false;
878 if (is_string_) {
879 base::string16 read_value;
880 found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS;
881 if (found) {
882 correct_value =
883 read_value.size() == value_.size() &&
884 ::CompareString(
885 LOCALE_USER_DEFAULT, NORM_IGNORECASE, read_value.data(),
886 base::saturated_cast<int>(read_value.size()), value_.data(),
887 base::saturated_cast<int>(value_.size())) == CSTR_EQUAL;
888 }
889 } else {
890 DWORD read_value;
891 found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS;
892 if (found)
893 correct_value = read_value == int_value_;
894 }
895 return found ? (correct_value ? SAME_VALUE : DIFFERENT_VALUE)
896 : DOES_NOT_EXIST;
897 }
818 898
819 // This method converts all the RegistryEntries from the given list to 899 // This method converts all the RegistryEntries from the given list to
820 // Set/CreateRegWorkItems and runs them using WorkItemList. 900 // Set/CreateRegWorkItems and runs them using WorkItemList.
821 bool AddRegistryEntries(HKEY root, const ScopedVector<RegistryEntry>& entries) { 901 bool AddRegistryEntries(HKEY root, const ScopedVector<RegistryEntry>& entries) {
822 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList()); 902 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList());
823 903
824 for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin(); 904 for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin();
825 itr != entries.end(); ++itr) 905 itr != entries.end(); ++itr)
826 (*itr)->AddToWorkItemList(root, items.get()); 906 (*itr)->AddToWorkItemList(root, items.get());
827 907
(...skipping 1692 matching lines...) Expand 10 before | Expand all | Expand 10 after
2520 base::string16 key_path(ShellUtil::kRegClasses); 2600 base::string16 key_path(ShellUtil::kRegClasses);
2521 key_path.push_back(base::FilePath::kSeparators[0]); 2601 key_path.push_back(base::FilePath::kSeparators[0]);
2522 key_path.append(prog_id); 2602 key_path.append(prog_id);
2523 return InstallUtil::DeleteRegistryKey( 2603 return InstallUtil::DeleteRegistryKey(
2524 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default); 2604 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default);
2525 2605
2526 // TODO(mgiuca): Remove the extension association entries. This requires that 2606 // TODO(mgiuca): Remove the extension association entries. This requires that
2527 // the extensions associated with a particular prog_id are stored in that 2607 // the extensions associated with a particular prog_id are stored in that
2528 // prog_id's key. 2608 // prog_id's key.
2529 } 2609 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698