15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file defines functions that integrate Chrome in Windows shell. These
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// functions can be used by Chrome as well as Chrome installer. All of the
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// work is done by the local functions defined in anonymous namespace in
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this class.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/shell_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <shlobj.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/md5.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/synchronization/cancellation_flag.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_co_mem.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/shortcut.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/win_util.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/browser_distribution.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/install_util.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/l10n_string_util.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/master_preferences.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/master_preferences_constants.h"
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/installer/util/util_constants.h"
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/installer/util/work_item.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "installer_util_strings.h"  // NOLINT
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::RegKey;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An enum used to tell QuickIsChromeRegistered() which level of registration
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the caller wants to confirm.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum RegistrationConfirmationLevel {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only look for Chrome's ProgIds.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is sufficient when we are trying to determine the suffix of the
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently running Chrome as shell integration registrations might not be
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // present.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CONFIRM_PROGID_REGISTRATION = 0,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Confirm that Chrome is fully integrated with Windows (i.e. registered with
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Defaut Programs). These registrations can be in HKCU as of Windows 8.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: Shell registration implies ProgId registration.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CONFIRM_SHELL_REGISTRATION,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Same as CONFIRM_SHELL_REGISTRATION, but only look in HKLM (used when
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // uninstalling to know whether elevation is required to clean up the
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // registry).
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CONFIRM_SHELL_REGISTRATION_IN_HKLM,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kReinstallCommand[] = L"ReinstallCommand";
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if Chrome Metro is supported on this OS (Win 8 8370 or greater).
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(gab): Change this to a simple check for Win 8 once old Win8 builds
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// become irrelevant.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsChromeMetroSupported() {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSVERSIONINFOEX min_version_info = {};
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  min_version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  min_version_info.dwMajorVersion = 6;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  min_version_info.dwMinorVersion = 2;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  min_version_info.dwBuildNumber = 8370;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  min_version_info.wServicePackMajor = 0;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  min_version_info.wServicePackMinor = 0;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORDLONG condition_mask = 0;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_GREATER_EQUAL);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER |
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the current (or installed) browser's ProgId (e.g.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "ChromeHTML|suffix|").
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |suffix| can be the empty string.
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetBrowserProgId(const base::string16& suffix) {
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 chrome_html(dist->GetBrowserProgIdPrefix());
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome_html.append(suffix);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProgIds cannot be longer than 39 characters.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ref: http://msdn.microsoft.com/en-us/library/aa911706.aspx.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make all new registrations comply with this requirement (existing
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // registrations must be preserved).
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 new_style_suffix;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShellUtil::GetUserSpecificRegistrySuffix(&new_style_suffix) &&
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suffix == new_style_suffix && chrome_html.length() > 39) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome_html.erase(39);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return chrome_html;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is used to initialize and cache a base 32 encoding of the md5 hash
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of this user's sid preceded by a dot.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is guaranteed to be unique on the machine and 27 characters long
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (including the '.').
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is then meant to be used as a suffix on all registrations that may
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// conflict with another user-level Chrome install.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UserSpecificRegistrySuffix {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All the initialization is done in the constructor to be able to build the
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // suffix in a thread-safe manner when used in conjunction with a
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LazyInstance.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UserSpecificRegistrySuffix();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets |suffix| to the pre-computed suffix cached in this object.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true unless the initialization originally failed.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool GetSuffix(base::string16* suffix);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 suffix_;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(UserSpecificRegistrySuffix);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};  // class UserSpecificRegistrySuffix
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserSpecificRegistrySuffix::UserSpecificRegistrySuffix() {
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 user_sid;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::win::GetUserSidString(&user_sid)) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(sizeof(base::MD5Digest) == 16, size_of_MD5_not_as_expected_);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Digest md5_digest;
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string user_sid_ascii(base::UTF16ToASCII(user_sid));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Sum(user_sid_ascii.c_str(), user_sid_ascii.length(), &md5_digest);
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16 base32_md5(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellUtil::ByteArrayToBase32(md5_digest.a, arraysize(md5_digest.a)));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The value returned by the base32 algorithm above must never change and
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must always be 26 characters long (i.e. if someone ever moves this to
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // base and implements the full base32 algorithm (i.e. with appended '='
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // signs in the output), they must provide a flag to allow this method to
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // still request the output with no appended '=' signs).
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(base32_md5.length(), 26U);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix_.reserve(base32_md5.length() + 1);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix_.assign(1, L'.');
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix_.append(base32_md5);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool UserSpecificRegistrySuffix::GetSuffix(base::string16* suffix) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (suffix_.empty()) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix->assign(suffix_);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class represents a single registry entry. The objective is to
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// encapsulate all the registry entries required for registering Chrome at one
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// place. This class can not be instantiated outside the class and the objects
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of this class type can be obtained only by calling a static method of this
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// class.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RegistryEntry {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A bit-field enum of places to look for this key in the Windows registry.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum LookForIn {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOOK_IN_HKCU = 1 << 0,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOOK_IN_HKLM = 1 << 1,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the Windows browser client registration key for Chrome.  For
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // example: "Software\Clients\StartMenuInternet\Chromium[.user]".  Strictly
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // speaking, we should use the name of the executable (e.g., "chrome.exe"),
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but that ship has sailed.  The cost of switching now is re-prompting users
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to make Chrome their default browser, which isn't polite.  |suffix| is the
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in shell_util.h for details.
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static base::string16 GetBrowserClientKey(BrowserDistribution* dist,
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const base::string16& suffix) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(suffix.empty() || suffix[0] == L'.');
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16(ShellUtil::kRegStartMenuInternet)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .append(1, L'\\')
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .append(dist->GetBaseAppName())
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .append(suffix);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the Windows Default Programs capabilities key for Chrome.  For
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // example:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities".
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static base::string16 GetCapabilitiesKey(BrowserDistribution* dist,
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           const base::string16& suffix) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities");
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method returns a list of all the registry entries that
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are needed to register this installation's ProgId and AppId.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These entries need to be registered in HKLM prior to Win8.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void GetProgIdEntries(BrowserDistribution* dist,
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               const base::string16& chrome_exe,
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               const base::string16& suffix,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               ScopedVector<RegistryEntry>* entries) {
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 icon_path(
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ShellUtil::FormatIconLocation(
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            chrome_exe,
2283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 open_cmd(ShellUtil::GetChromeShellOpenCmd(chrome_exe));
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 delegate_command(
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ShellUtil::GetChromeDelegateCommand(chrome_exe));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For user-level installs: entries for the app id and DelegateExecute verb
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // handler will be in HKCU; thus we do not need a suffix on those entries.
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 app_id(
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ShellUtil::GetBrowserModelId(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str())));
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 delegate_guid;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool set_delegate_execute =
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IsChromeMetroSupported() &&
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dist->GetCommandExecuteImplClsid(&delegate_guid);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (set_delegate_execute) {
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 model_id_shell(ShellUtil::kRegClasses);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      model_id_shell.push_back(base::FilePath::kSeparators[0]);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_id_shell.append(app_id);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_id_shell.append(ShellUtil::kRegExePath);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_id_shell.append(ShellUtil::kRegShellPath);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(model_id_shell,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           ShellUtil::kRegVerbOpen));
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // registered to handle some verbs. This registration has the side-effect
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // that these verbs now show up in the shortcut's context menu. We
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // mitigate this side-effect by making the context menu entries
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // user readable/localized strings. See relevant MSDN article:
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const struct {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const wchar_t* verb;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int name_id;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } verbs[] = {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          { ShellUtil::kRegVerbOpen, -1 },
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE },
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      };
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < arraysize(verbs); ++i) {
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::string16 sub_path(model_id_shell);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sub_path.push_back(base::FilePath::kSeparators[0]);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sub_path.append(verbs[i].verb);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (verbs[i].name_id != -1) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // TODO(grt): http://crbug.com/75152 Write a reference to a localized
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // resource.
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::string16 verb_name(
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              installer::GetLocalizedString(verbs[i].name_id));
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          entries->push_back(new RegistryEntry(sub_path, verb_name.c_str()));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        entries->push_back(new RegistryEntry(
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sub_path, L"CommandId", L"Browser.Launch"));
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sub_path.push_back(base::FilePath::kSeparators[0]);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sub_path.append(ShellUtil::kRegCommand);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        entries->push_back(new RegistryEntry(sub_path, delegate_command));
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        entries->push_back(new RegistryEntry(
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sub_path, ShellUtil::kRegDelegateExecute, delegate_guid));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // File association ProgId
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 chrome_html_prog_id(ShellUtil::kRegClasses);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome_html_prog_id.push_back(base::FilePath::kSeparators[0]);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome_html_prog_id.append(GetBrowserProgId(suffix));
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
298d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        chrome_html_prog_id, dist->GetBrowserProgIdDesc()));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path));
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd));
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (set_delegate_execute) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_html_prog_id + ShellUtil::kRegShellOpen,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ShellUtil::kRegDelegateExecute, delegate_guid));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The following entries are required as of Windows 8, but do not
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // depend on the DelegateExecute verb handler being set.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_html_prog_id, ShellUtil::kRegAppUserModelId, app_id));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add \Software\Classes\ChromeHTML\Application entries
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 chrome_application(chrome_html_prog_id +
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        ShellUtil::kRegApplication);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_application, ShellUtil::kRegAppUserModelId, app_id));
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_application, ShellUtil::kRegApplicationIcon, icon_path));
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(grt): http://crbug.com/75152 Write a reference to a localized
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // resource for name, description, and company.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_application, ShellUtil::kRegApplicationName,
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          dist->GetDisplayName()));
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_application, ShellUtil::kRegApplicationDescription,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          dist->GetAppDescription()));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome_application, ShellUtil::kRegApplicationCompany,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          dist->GetPublisherName()));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method returns a list of the registry entries needed to declare a
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // capability of handling a protocol on Windows.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void GetProtocolCapabilityEntries(
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserDistribution* dist,
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& suffix,
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& protocol,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScopedVector<RegistryEntry>* entries) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"),
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        protocol, GetBrowserProgId(suffix)));
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method returns a list of the registry entries required to register
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this installation in "RegisteredApplications" on Windows (to appear in
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Default Programs, StartMenuInternet, etc.).
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These entries need to be registered in HKLM prior to Win8.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |suffix| is not empty, these entries are guaranteed to be unique on this
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // machine.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void GetShellIntegrationEntries(BrowserDistribution* dist,
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const base::string16& chrome_exe,
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const base::string16& suffix,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         ScopedVector<RegistryEntry>* entries) {
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 icon_path(
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ShellUtil::FormatIconLocation(
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            chrome_exe,
3613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 quoted_exe_path(L"\"" + chrome_exe + L"\"");
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register for the Start Menu "Internet" link (pre-Win7).
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 start_menu_entry(GetBrowserClientKey(dist, suffix));
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register Chrome's display name.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).aspx#registering_the_display_name
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
3703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        start_menu_entry, dist->GetDisplayName()));
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register the "open" verb for launching Chrome via the "Internet" link.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register Chrome's icon for the Start Menu "Internet" link.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path));
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register installation information.
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 install_info(start_menu_entry + L"\\InstallInfo");
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: not using CommandLine since it has ambiguous rules for quoting
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // strings.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(install_info, kReinstallCommand,
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        quoted_exe_path + L" --" +
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::ASCIIToWide(switches::kMakeDefaultBrowser)));
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(install_info, L"HideIconsCommand",
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        quoted_exe_path + L" --" +
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::ASCIIToWide(switches::kHideIcons)));
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(install_info, L"ShowIconsCommand",
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        quoted_exe_path + L" --" +
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::ASCIIToWide(switches::kShowIcons)));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(install_info, L"IconsVisible", 1));
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register with Default Programs.
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 reg_app_name(dist->GetBaseAppName().append(suffix));
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tell Windows where to find Chrome's Default Programs info.
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 capabilities(GetCapabilitiesKey(dist, suffix));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(ShellUtil::kRegRegisteredApplications,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reg_app_name, capabilities));
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Write out Chrome's Default Programs info.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(grt): http://crbug.com/75152 Write a reference to a localized
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // resource rather than this.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        capabilities, ShellUtil::kRegApplicationDescription,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dist->GetLongAppDescription()));
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        capabilities, ShellUtil::kRegApplicationIcon, icon_path));
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        capabilities, ShellUtil::kRegApplicationName,
4093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        dist->GetDisplayName()));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu",
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        L"StartMenuInternet", reg_app_name));
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 html_prog_id(GetBrowserProgId(suffix));
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          capabilities + L"\\FileAssociations",
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ShellUtil::kPotentialFileAssociations[i], html_prog_id));
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        i++) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          capabilities + L"\\URLAssociations",
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ShellUtil::kPotentialProtocolAssociations[i], html_prog_id));
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method returns a list of the registry entries required for this
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // installation to be registered in the Windows shell.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In particular:
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  - App Paths
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  - File Associations
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    http://msdn.microsoft.com/en-us/library/bb166549
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These entries need to be registered in HKLM prior to Win8.
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static void GetAppRegistrationEntries(const base::string16& chrome_exe,
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const base::string16& suffix,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        ScopedVector<RegistryEntry>* entries) {
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath chrome_path(chrome_exe);
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    app_path_key.push_back(base::FilePath::kSeparators[0]);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    app_path_key.append(chrome_path.BaseName().value());
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(app_path_key, chrome_exe));
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(app_path_key,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ShellUtil::kAppPathsRegistryPathName, chrome_path.DirName().value()));
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16 html_prog_id(GetBrowserProgId(suffix));
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 key(ShellUtil::kRegClasses);
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key.push_back(base::FilePath::kSeparators[0]);
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      key.append(ShellUtil::kPotentialFileAssociations[i]);
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key.push_back(base::FilePath::kSeparators[0]);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key.append(ShellUtil::kRegOpenWithProgids);
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      entries->push_back(
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new RegistryEntry(key, html_prog_id, base::string16()));
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method returns a list of all the user level registry entries that
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are needed to make Chromium the default handler for a protocol on XP.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void GetXPStyleUserProtocolEntries(
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& protocol,
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& chrome_icon,
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& chrome_open,
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScopedVector<RegistryEntry>* entries) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Protocols associations.
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 url_key(ShellUtil::kRegClasses);
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url_key.push_back(base::FilePath::kSeparators[0]);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_key.append(protocol);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This registry value tells Windows that this 'class' is a URL scheme
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // so IE, explorer and other apps will route it to our handler.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // <root hkey>\Software\Classes\<protocol>\URL Protocol
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(url_key,
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        ShellUtil::kRegUrlProtocol, base::string16()));
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // <root hkey>\Software\Classes\<protocol>\DefaultIcon
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(icon_key, chrome_icon));
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // <root hkey>\Software\Classes\<protocol>\shell\open\command
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 shell_key = url_key + ShellUtil::kRegShellOpen;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(shell_key, chrome_open));
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec";
487cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    entries->push_back(new RegistryEntry(dde_key, base::string16()));
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // <root hkey>\Software\Classes\<protocol>\shell\@
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(protocol_shell_key, L"open"));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method returns a list of all the user level registry entries that
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are needed to make Chromium default browser on XP.
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some of these entries are irrelevant in recent versions of Windows, but
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we register them anyways as some legacy apps are hardcoded to lookup those
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // values.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void GetXPStyleDefaultBrowserUserEntries(
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserDistribution* dist,
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& chrome_exe,
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& suffix,
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScopedVector<RegistryEntry>* entries) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // File extension associations.
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 html_prog_id(GetBrowserProgId(suffix));
506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 ext_key(ShellUtil::kRegClasses);
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ext_key.push_back(base::FilePath::kSeparators[0]);
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ext_key.append(ShellUtil::kDefaultFileAssociations[i]);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries->push_back(new RegistryEntry(ext_key, html_prog_id));
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Protocols associations.
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 chrome_icon =
5163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ShellUtil::FormatIconLocation(
5173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            chrome_exe,
5183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i],
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    chrome_icon, chrome_open, entries);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // start->Internet shortcut.
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 start_menu(ShellUtil::kRegStartMenuInternet);
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 app_name = dist->GetBaseAppName() + suffix;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries->push_back(new RegistryEntry(start_menu, app_name));
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate work_item tasks required to create current registry entry and
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // add them to the given work item list.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddToWorkItemList(HKEY root, WorkItemList *items) const {
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
534ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (is_string_) {
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      items->AddSetRegValueWorkItem(
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          root, key_path_, WorkItem::kWow64Default, name_, value_, true);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      items->AddSetRegValueWorkItem(
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          root, key_path_, WorkItem::kWow64Default, name_, int_value_, true);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
543ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Checks if the current registry entry exists in HKCU\|key_path_|\|name_|
544ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // and value is |value_|. If the key does NOT exist in HKCU, checks for
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the correct name and value in HKLM.
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // key, unspecified roots are not looked into (i.e. the the key is assumed not
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to exist in them).
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |look_for_in| must at least specify one root to look into.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows'
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // behavior when searching in HKCR (HKCU takes precedence over HKLM). For
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // registrations outside of HKCR on versions of Windows prior to Win8,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chrome's values go in HKLM. This function will make unnecessary (but
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // harmless) queries into HKCU in that case.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ExistsInRegistry(uint32 look_for_in) const {
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(look_for_in);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegistryStatus status = DOES_NOT_EXIST;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (look_for_in & LOOK_IN_HKCU)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status == SAME_VALUE;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // States this RegistryKey can be in compared to the registry.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum RegistryStatus {
569ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // |name_| does not exist in the registry
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DOES_NOT_EXIST,
571ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // |name_| exists, but its value != |value_|
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DIFFERENT_VALUE,
573ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // |name_| exists and its value is |value_|
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAME_VALUE,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a object that represent default value of a key
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegistryEntry(const base::string16& key_path, const base::string16& value)
579ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      : key_path_(key_path), name_(),
580ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        is_string_(true), value_(value), int_value_(0) {
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a object that represent a key of type REG_SZ
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegistryEntry(const base::string16& key_path, const base::string16& name,
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                const base::string16& value)
586ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      : key_path_(key_path), name_(name),
587ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        is_string_(true), value_(value), int_value_(0) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a object that represent a key of integer type
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegistryEntry(const base::string16& key_path, const base::string16& name,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                DWORD value)
593ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      : key_path_(key_path), name_(name),
594ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        is_string_(false), value_(), int_value_(value) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 key_path_;  // key path for the registry entry
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 name_;      // name of the registry entry
599ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool is_string_;     // true if current registry entry is of type REG_SZ
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 value_;     // string value (useful if is_string_ = true)
601ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DWORD int_value_;    // integer value (useful if is_string_ = false)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper function for ExistsInRegistry().
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the RegistryStatus of the current registry entry in
605ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // |root|\|key_path_|\|name_|.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryStatus StatusInRegistryUnderRoot(HKEY root) const {
607ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool found = false;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool correct_value = false;
610ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (is_string_) {
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 read_value;
612ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS;
613116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (found) {
614116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        correct_value = read_value.size() == value_.size() &&
615116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            std::equal(value_.begin(), value_.end(), read_value.begin(),
616116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       base::CaseInsensitiveCompare<wchar_t>());
617116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD read_value;
620ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS;
621116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (found)
622116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        correct_value = read_value == int_value_;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return found ?
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (correct_value ? SAME_VALUE : DIFFERENT_VALUE) : DOES_NOT_EXIST;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(RegistryEntry);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};  // class RegistryEntry
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method converts all the RegistryEntries from the given list to
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Set/CreateRegWorkItems and runs them using WorkItemList.
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AddRegistryEntries(HKEY root, const ScopedVector<RegistryEntry>& entries) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList());
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       itr != entries.end(); ++itr)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*itr)->AddToWorkItemList(root, items.get());
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Apply all the registry changes and if there is a problem, rollback
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!items->Do()) {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items->Rollback();
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks that all |entries| are present on this computer.
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |look_for_in| is passed to RegistryEntry::ExistsInRegistry(). Documentation
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for it can be found there.
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AreEntriesRegistered(const ScopedVector<RegistryEntry>& entries,
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          uint32 look_for_in) {
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool registered = true;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin();
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       registered && itr != entries.end(); ++itr) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We do not need registered = registered && ... since the loop condition
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is set to exit early.
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registered = (*itr)->ExistsInRegistry(look_for_in);
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return registered;
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks that all required registry entries for Chrome are already present
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// on this computer. See RegistryEntry::ExistsInRegistry for the behavior of
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |look_for_in|.
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: between r133333 and r154145 we were registering parts of Chrome in HKCU
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and parts in HKLM for user-level installs; we now always register everything
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// under a single registry root. Not doing so caused http://crbug.com/144910 for
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// users who first-installed Chrome in that revision range (those users are
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// still impacted by http://crbug.com/144910). This method will keep returning
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// true for affected users (i.e. who have all the registrations, but over both
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// registry roots).
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsChromeRegistered(BrowserDistribution* dist,
6755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const base::string16& chrome_exe,
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const base::string16& suffix,
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        uint32 look_for_in) {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<RegistryEntry> entries;
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries);
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AreEntriesRegistered(entries, look_for_in);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method checks if Chrome is already registered on the local machine
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for the requested protocol. It just checks the one value required for this.
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|.
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsChromeRegisteredForProtocol(BrowserDistribution* dist,
6895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   const base::string16& suffix,
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   const base::string16& protocol,
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   uint32 look_for_in) {
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<RegistryEntry> entries;
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryEntry::GetProtocolCapabilityEntries(dist, suffix, protocol, &entries);
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AreEntriesRegistered(entries, look_for_in);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method registers Chrome on Vista by launching an elevated setup.exe.
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// That will show the user the standard Vista elevation prompt. If the user
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accepts it the new process will make the necessary changes and return SUCCESS
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that we capture and return.
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If protocol is non-empty we will also register Chrome as being capable of
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handling the protocol.
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ElevateAndRegisterChrome(BrowserDistribution* dist,
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const base::string16& chrome_exe,
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const base::string16& suffix,
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const base::string16& protocol) {
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only user-level installs prior to Windows 8 should need to elevate to
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // register.
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(InstallUtil::IsPerUserInstall(chrome_exe.c_str()));
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LT(base::win::GetVersion(), base::win::VERSION_WIN8);
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath exe_path =
71268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::FilePath(chrome_exe).DirName().Append(installer::kSetupExe);
7137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(exe_path)) {
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HKEY reg_root = InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ?
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
716cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    RegKey key(reg_root,
717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               dist->GetUninstallRegPath().c_str(),
718cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               KEY_READ | KEY_WOW64_32KEY);
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 uninstall_string;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key.ReadValue(installer::kUninstallStringField, &uninstall_string);
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommandLine command_line = CommandLine::FromString(uninstall_string);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exe_path = command_line.GetProgram();
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (base::PathExists(exe_path)) {
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommandLine cmd(exe_path);
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd.AppendSwitchNative(installer::switches::kRegisterChromeBrowser,
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           chrome_exe);
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!suffix.empty()) {
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd.AppendSwitchNative(
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          installer::switches::kRegisterChromeBrowserSuffix, suffix);
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!protocol.empty()) {
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd.AppendSwitchNative(
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        installer::switches::kRegisterURLProtocol, protocol);
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD ret_val = 0;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InstallUtil::ExecuteExeAsAdmin(cmd, &ret_val);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ret_val == 0)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Launches the Windows 7 and Windows 8 dialog for picking the application to
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handle the given protocol. Most importantly, this is used to set the default
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handler for http (and, implicitly with it, https). In that case it is also
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// known as the 'how do you want to open webpages' dialog.
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is required that Chrome be already *registered* for the given protocol.
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LaunchSelectDefaultProtocolHandlerDialog(const wchar_t* protocol) {
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(protocol);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OPENASINFO open_as_info = {};
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  open_as_info.pcszFile = protocol;
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  open_as_info.oaifInFlags =
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OAIF_URL_PROTOCOL | OAIF_FORCE_REGISTRATION | OAIF_REGISTER_EXT;
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = SHOpenWithDialog(NULL, &open_as_info);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(WARNING, FAILED(hr)) << "Failed to set as default " << protocol
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << " handler; hr=0x" << std::hex << hr;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Launches the Windows 7 and Windows 8 application association dialog, which
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is the only documented way to make a browser the default browser on
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows 8.
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool LaunchApplicationAssociationDialog(const base::string16& app_id) {
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IApplicationAssociationRegistrationUI> aarui;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = aarui.CreateInstance(CLSID_ApplicationAssociationRegistrationUI);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = aarui->LaunchAdvancedAssociationUI(app_id.c_str());
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SUCCEEDED(hr);
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the current install's |chrome_exe| has been registered with
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |suffix|.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |confirmation_level| is the level of verification desired as described in
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the RegistrationConfirmationLevel enum above.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |suffix| can be the empty string (this is used to support old installs
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// where we used to not suffix user-level installs if they were the first to
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// request the non-suffixed registry entries on the machine).
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: This a quick check that only validates that a single registry entry
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// points to |chrome_exe|. This should only be used at run-time to determine
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// how Chrome is registered, not to know whether the registration is complete
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at install-time (IsChromeRegistered() can be used for that).
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool QuickIsChromeRegistered(BrowserDistribution* dist,
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             const base::string16& chrome_exe,
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             const base::string16& suffix,
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             RegistrationConfirmationLevel confirmation_level) {
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the appropriate key to look for based on the level desired.
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 reg_key;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (confirmation_level) {
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIRM_PROGID_REGISTRATION:
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Software\Classes\ChromeHTML|suffix|
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reg_key = ShellUtil::kRegClasses;
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reg_key.push_back(base::FilePath::kSeparators[0]);
801d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      reg_key.append(dist->GetBrowserProgIdPrefix());
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reg_key.append(suffix);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIRM_SHELL_REGISTRATION:
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIRM_SHELL_REGISTRATION_IN_HKLM:
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Software\Clients\StartMenuInternet\Google Chrome|suffix|
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reg_key = RegistryEntry::GetBrowserClientKey(dist, suffix);
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reg_key.append(ShellUtil::kRegShellOpen);
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProgId registrations are allowed to reside in HKCU for user-level installs
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (and values there have priority over values in HKLM). The same is true for
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shell integration entries as of Windows 8.
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (confirmation_level == CONFIRM_PROGID_REGISTRATION ||
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (confirmation_level == CONFIRM_SHELL_REGISTRATION &&
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       base::win::GetVersion() >= base::win::VERSION_WIN8)) {
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const RegKey key_hkcu(HKEY_CURRENT_USER, reg_key.c_str(), KEY_QUERY_VALUE);
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 hkcu_value;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If |reg_key| is present in HKCU, assert that it points to |chrome_exe|.
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Otherwise, fall back on an HKLM lookup below.
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key_hkcu.ReadValue(L"", &hkcu_value) == ERROR_SUCCESS) {
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return InstallUtil::ProgramCompare(
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::FilePath(chrome_exe)).Evaluate(hkcu_value);
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Assert that |reg_key| points to |chrome_exe| in HKLM.
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE);
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 hklm_value;
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return InstallUtil::ProgramCompare(
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath(chrome_exe)).Evaluate(hklm_value);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sets |suffix| to a 27 character string that is specific to this user on this
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// machine (on user-level installs only).
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// To support old-style user-level installs however, |suffix| is cleared if the
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// user currently owns the non-suffixed HKLM registrations.
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |suffix| can also be set to the user's username if the current install is
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// suffixed as per the old-style registrations.
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |suffix| is cleared on system-level installs.
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |suffix| should then be appended to all Chrome properties that may conflict
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with other Chrome user-level installs.
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true unless one of the underlying calls fails.
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetInstallationSpecificSuffix(BrowserDistribution* dist,
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   const base::string16& chrome_exe,
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   base::string16* suffix) {
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ||
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      QuickIsChromeRegistered(dist, chrome_exe, base::string16(),
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              CONFIRM_SHELL_REGISTRATION)) {
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No suffix on system-level installs and user-level installs already
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // registered with no suffix.
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suffix->clear();
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the old suffix for the check below.
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShellUtil::GetOldUserSpecificRegistrySuffix(suffix)) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (QuickIsChromeRegistered(dist, chrome_exe, *suffix,
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              CONFIRM_SHELL_REGISTRATION)) {
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Username suffix for installs that are suffixed as per the old-style.
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellUtil::GetUserSpecificRegistrySuffix(suffix);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the root registry key (HKLM or HKCU) under which registrations must
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be placed for this install. As of Windows 8 everything can go in HKCU for
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// per-user installs.
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HKEY DetermineRegistrationRoot(bool is_per_user) {
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ?
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Associates Chrome with supported protocols and file associations. This should
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not be required on Vista+ but since some applications still read
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Software\Classes\http key directly, we have to do this on Vista+ as well.
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RegisterChromeAsDefaultXPStyle(BrowserDistribution* dist,
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    int shell_change,
8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    const base::string16& chrome_exe) {
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ret = true;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<RegistryEntry> entries;
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryEntry::GetXPStyleDefaultBrowserUserEntries(
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dist, chrome_exe,
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe), &entries);
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the default browser for current user.
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((shell_change & ShellUtil::CURRENT_USER) &&
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !AddRegistryEntries(HKEY_CURRENT_USER, entries)) {
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = false;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Could not make Chrome default browser (XP/current user).";
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chrome as default browser at system level.
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((shell_change & ShellUtil::SYSTEM_LEVEL) &&
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !AddRegistryEntries(HKEY_LOCAL_MACHINE, entries)) {
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = false;
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Could not make Chrome default browser (XP/system level).";
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Associates Chrome with |protocol| in the registry. This should not be
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// required on Vista+ but since some applications still read these registry
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// keys directly, we have to do this on Vista+ as well.
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See http://msdn.microsoft.com/library/aa767914.aspx for more details.
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool RegisterChromeAsDefaultProtocolClientXPStyle(
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserDistribution* dist,
9205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe,
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& protocol) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<RegistryEntry> entries;
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16 chrome_open(
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ShellUtil::GetChromeShellOpenCmd(chrome_exe));
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16 chrome_icon(
9263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ShellUtil::FormatIconLocation(
9273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          chrome_exe,
9283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistryEntry::GetXPStyleUserProtocolEntries(protocol, chrome_icon,
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               chrome_open, &entries);
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the default protocol handler for current user.
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!AddRegistryEntries(HKEY_CURRENT_USER, entries)) {
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Could not make Chrome default protocol client (XP).";
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns |properties.shortcut_name| if the property is set, otherwise it
9413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// returns dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME). In any
9423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// case, it makes sure the return value is suffixed with ".lnk".
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ExtractShortcutNameFromProperties(
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserDistribution* dist,
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ShellUtil::ShortcutProperties& properties) {
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dist);
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 shortcut_name;
9483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (properties.has_shortcut_name()) {
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_name = properties.shortcut_name;
9503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
9513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    shortcut_name =
9523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME);
9533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EndsWith(shortcut_name, installer::kLnkExt, false))
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_name.append(installer::kLnkExt);
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shortcut_name;
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts ShellUtil::ShortcutOperation to the best-matching value in
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// base::win::ShortcutOperation.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::win::ShortcutOperation TranslateShortcutOperation(
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellUtil::ShortcutOperation operation) {
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (operation) {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS:  // Falls through.
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL:
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return base::win::SHORTCUT_CREATE_ALWAYS;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING:
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return base::win::SHORTCUT_UPDATE_EXISTING;
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING:
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return base::win::SHORTCUT_REPLACE_EXISTING;
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return base::win::SHORTCUT_REPLACE_EXISTING;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a base::win::ShortcutProperties struct containing the properties
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to set on the shortcut based on the provided ShellUtil::ShortcutProperties.
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::win::ShortcutProperties TranslateShortcutProperties(
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ShellUtil::ShortcutProperties& properties) {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ShortcutProperties shortcut_properties;
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.has_target()) {
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_target(properties.target);
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!properties.target.DirName().empty());
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_working_dir(properties.target.DirName());
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.has_arguments())
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_arguments(properties.arguments);
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.has_description())
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_description(properties.description);
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.has_icon())
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_icon(properties.icon, properties.icon_index);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.has_app_id())
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_app_id(properties.app_id);
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.has_dual_mode())
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_properties.set_dual_mode(properties.dual_mode);
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shortcut_properties;
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Cleans up an old verb (run) we used to register in
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <root>\Software\Classes\Chrome<.suffix>\.exe\shell\run on Windows 8.
10145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RemoveRunVerbOnWindows8(BrowserDistribution* dist,
10155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             const base::string16& chrome_exe) {
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsChromeMetroSupported()) {
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_per_user_install =InstallUtil::IsPerUserInstall(chrome_exe.c_str());
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HKEY root_key = DetermineRegistrationRoot(is_per_user_install);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There's no need to rollback, so forgo the usual work item lists and just
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // remove the key from the registry.
10215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 run_verb_key(ShellUtil::kRegClasses);
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    run_verb_key.push_back(base::FilePath::kSeparators[0]);
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    run_verb_key.append(ShellUtil::GetBrowserModelId(
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dist, is_per_user_install));
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    run_verb_key.append(ShellUtil::kRegExePath);
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    run_verb_key.append(ShellUtil::kRegShellPath);
10272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    run_verb_key.push_back(base::FilePath::kSeparators[0]);
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    run_verb_key.append(ShellUtil::kRegVerbRun);
1029cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InstallUtil::DeleteRegistryKey(root_key, run_verb_key,
1030cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                   WorkItem::kWow64Default);
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the short (8.3) form of |path|, putting the result in |short_path| and
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returning true on success.  |short_path| is not modified on failure.
10365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShortNameFromPath(const base::FilePath& path, base::string16* short_path) {
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(short_path);
10385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 result(MAX_PATH, L'\0');
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD short_length = GetShortPathName(path.value().c_str(), &result[0],
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        result.size());
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (short_length == 0 || short_length > result.size()) {
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(ERROR) << "Error getting short (8.3) path";
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.resize(short_length);
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  short_path->swap(result);
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Probe using IApplicationAssociationRegistration::QueryCurrentDefault
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (Windows 8); see ProbeProtocolHandlers.  This mechanism is not suitable for
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use on previous versions of Windows despite the presence of
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// QueryCurrentDefault on them since versions of Windows prior to Windows 8
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// did not perform validation on the ProgID registered as the current default.
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// As a result, stale ProgIDs could be returned, leading to false positives.
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellUtil::DefaultState ProbeCurrentDefaultHandlers(
1058a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::FilePath& chrome_exe,
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* const* protocols,
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t num_protocols) {
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = registration.CreateInstance(
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ShellUtil::UNKNOWN_DEFAULT;
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
10685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 prog_id(dist->GetBrowserProgIdPrefix());
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prog_id += ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe.value());
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < num_protocols; ++i) {
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::ScopedCoMem<wchar_t> current_app;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = registration->QueryCurrentDefault(protocols[i], AT_URLPROTOCOL,
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           AL_EFFECTIVE, &current_app);
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr) || prog_id.compare(current_app) != 0)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ShellUtil::NOT_DEFAULT;
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellUtil::IS_DEFAULT;
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Probe using IApplicationAssociationRegistration::QueryAppIsDefault (Vista and
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows 7); see ProbeProtocolHandlers.
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellUtil::DefaultState ProbeAppIsDefaultHandlers(
1085a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::FilePath& chrome_exe,
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* const* protocols,
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t num_protocols) {
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = registration.CreateInstance(
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ShellUtil::UNKNOWN_DEFAULT;
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
10955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 app_name(
10965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ShellUtil::GetApplicationName(dist, chrome_exe.value()));
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL result;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < num_protocols; ++i) {
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = TRUE;
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = registration->QueryAppIsDefault(protocols[i], AT_URLPROTOCOL,
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AL_EFFECTIVE, app_name.c_str(), &result);
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr) || result == FALSE)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ShellUtil::NOT_DEFAULT;
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellUtil::IS_DEFAULT;
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Probe the current commands registered to handle the shell "open" verb for
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |protocols| (Windows XP); see ProbeProtocolHandlers.
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellUtil::DefaultState ProbeOpenCommandHandlers(
1113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::FilePath& chrome_exe,
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* const* protocols,
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t num_protocols) {
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get its short (8.3) form.
11175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 short_app_path;
1118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!ShortNameFromPath(chrome_exe, &short_app_path))
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ShellUtil::UNKNOWN_DEFAULT;
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const HKEY root_key = HKEY_CLASSES_ROOT;
11225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 key_path;
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::RegKey key;
11245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 value;
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(CommandLine::NO_PROGRAM);
11265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 short_path;
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < num_protocols; ++i) {
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the command line from HKCU\<protocol>\shell\open\command.
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_path.assign(protocols[i]).append(ShellUtil::kRegShellOpen);
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((key.Open(root_key, key_path.c_str(),
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  KEY_QUERY_VALUE) != ERROR_SUCCESS) ||
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (key.ReadValue(L"", &value) != ERROR_SUCCESS)) {
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ShellUtil::NOT_DEFAULT;
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Need to normalize path in case it's been munged.
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_line = CommandLine::FromString(value);
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ShortNameFromPath(command_line.GetProgram(), &short_path))
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ShellUtil::UNKNOWN_DEFAULT;
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!base::FilePath::CompareEqualIgnoreCase(short_path, short_app_path))
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ShellUtil::NOT_DEFAULT;
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellUtil::IS_DEFAULT;
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper function that probes default protocol handler registration (in a
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// manner appropriate for the current version of Windows) to determine if
11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Chrome is the default handler for |protocols|.  Returns IS_DEFAULT
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only if Chrome is the default for all specified protocols.
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellUtil::DefaultState ProbeProtocolHandlers(
1154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::FilePath& chrome_exe,
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* const* protocols,
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t num_protocols) {
1157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if DCHECK_IS_ON
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!num_protocols || protocols);
1159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < num_protocols; ++i)
1160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(protocols[i] && *protocols[i]);
1161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::win::Version windows_version = base::win::GetVersion();
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (windows_version >= base::win::VERSION_WIN8)
1166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return ProbeCurrentDefaultHandlers(chrome_exe, protocols, num_protocols);
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (windows_version >= base::win::VERSION_VISTA)
1168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return ProbeAppIsDefaultHandlers(chrome_exe, protocols, num_protocols);
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return ProbeOpenCommandHandlers(chrome_exe, protocols, num_protocols);
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// (Windows 8+) Finds and stores an app shortcuts folder path in *|path|.
1174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true on success.
1175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool GetAppShortcutsFolder(BrowserDistribution* dist,
1176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           ShellUtil::ShellChange level,
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           base::FilePath *path) {
1178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(path);
1179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath folder;
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!PathService::Get(base::DIR_APP_SHORTCUTS, &folder)) {
1183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Could not get application shortcuts location.";
1184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  folder = folder.Append(
1188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ShellUtil::GetBrowserModelId(dist, level == ShellUtil::CURRENT_USER));
11897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::DirectoryExists(folder)) {
1190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    VLOG(1) << "No start screen shortcuts.";
1191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *path = folder;
1195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
1196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1198c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Shortcut filters for BatchShortcutAction().
1199c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1200c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochtypedef base::Callback<bool(const base::FilePath& /*shortcut_path*/,
12015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const base::string16& /*args*/)>
1202c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    ShortcutFilterCallback;
1203c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1204c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// FilterTargetEq is a shortcut filter that matches only shortcuts that have a
120558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// specific target, and optionally matches shortcuts that have non-empty
120658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// arguments.
1207c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochclass FilterTargetEq {
1208c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch public:
120958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  FilterTargetEq(const base::FilePath& desired_target_exe, bool require_args);
1210c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1211c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Returns true if filter rules are satisfied, i.e.:
121258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // - |target_path|'s target == |desired_target_compare_|, and
121358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // - |args| is non-empty (if |require_args_| == true).
12145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool Match(const base::FilePath& target_path,
12155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             const base::string16& args) const;
1216c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1217c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // A convenience routine to create a callback to call Match().
1218c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // The callback is only valid during the lifetime of the FilterTargetEq
1219c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // instance.
1220c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ShortcutFilterCallback AsShortcutFilterCallback();
1221c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1222c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch private:
1223c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  InstallUtil::ProgramCompare desired_target_compare_;
122458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
122558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool require_args_;
1226c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
1227c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
122858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)FilterTargetEq::FilterTargetEq(const base::FilePath& desired_target_exe,
122958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                               bool require_args)
123058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : desired_target_compare_(desired_target_exe),
123158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      require_args_(require_args) {}
1232c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1233c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochbool FilterTargetEq::Match(const base::FilePath& target_path,
12345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const base::string16& args) const {
123558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!desired_target_compare_.EvaluatePath(target_path))
123658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
123758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (require_args_ && args.empty())
123858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
123958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
1240c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
1241c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1242c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochShortcutFilterCallback FilterTargetEq::AsShortcutFilterCallback() {
1243c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return base::Bind(&FilterTargetEq::Match, base::Unretained(this));
1244c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
1245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Shortcut operations for BatchShortcutAction().
1247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1248c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochtypedef base::Callback<bool(const base::FilePath& /*shortcut_path*/)>
1249c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    ShortcutOperationCallback;
1250c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ShortcutOpUnpin(const base::FilePath& shortcut_path) {
1252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << "Trying to unpin " << shortcut_path.value();
1253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!base::win::TaskbarUnpinShortcutLink(shortcut_path.value().c_str())) {
1254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    VLOG(1) << shortcut_path.value() << " wasn't pinned (or the unpin failed).";
1255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // No error, since shortcut might not be pinned.
1256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
1258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ShortcutOpDelete(const base::FilePath& shortcut_path) {
12617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool ret = base::DeleteFile(shortcut_path, false);
1262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG_IF(ERROR, !ret) << "Failed to remove " << shortcut_path.value();
1263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ret;
1264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShortcutOpRetarget(const base::FilePath& old_target,
12675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const base::FilePath& new_target,
12685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const base::FilePath& shortcut_path) {
12695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ShortcutProperties new_prop;
12705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  new_prop.set_target(new_target);
12715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If the old icon matches old target, then update icon while keeping the old
12735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // icon index. Non-fatal if we fail to get the old icon.
12745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ShortcutProperties old_prop;
12755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (base::win::ResolveShortcutProperties(
12765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          shortcut_path,
12775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::win::ShortcutProperties::PROPERTIES_ICON,
12785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          &old_prop)) {
12795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (InstallUtil::ProgramCompare(old_target).EvaluatePath(old_prop.icon))
12805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new_prop.set_icon(new_target, old_prop.icon_index);
12815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
12825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to resolve " << shortcut_path.value();
12835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
12845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool result = base::win::CreateOrUpdateShortcutLink(
12865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shortcut_path, new_prop, base::win::SHORTCUT_UPDATE_EXISTING);
12875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG_IF(ERROR, !result) << "Failed to retarget " << shortcut_path.value();
12885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
12895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
12905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShortcutOpListOrRemoveUnknownArgs(
12925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool do_removal,
12935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::pair<base::FilePath, base::string16> >* shortcuts,
12945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& shortcut_path) {
12955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 args;
12965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::win::ResolveShortcut(shortcut_path, NULL, &args))
12975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
12985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CommandLine current_args(CommandLine::FromString(base::StringPrintf(
13005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      L"unused_program %ls", args.c_str())));
13015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char* const kept_switches[] = {
13025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      switches::kApp,
13035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      switches::kAppId,
13045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      switches::kShowAppList,
13055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      switches::kProfileDirectory,
13065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
13075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CommandLine desired_args(CommandLine::NO_PROGRAM);
13085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  desired_args.CopySwitchesFrom(current_args, kept_switches,
13095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                arraysize(kept_switches));
13105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (desired_args.argv().size() == current_args.argv().size())
13115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
13125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (shortcuts)
13135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    shortcuts->push_back(std::make_pair(shortcut_path, args));
13145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!do_removal)
13155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
13165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ShortcutProperties updated_properties;
13175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  updated_properties.set_arguments(desired_args.GetArgumentsString());
13185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::win::CreateOrUpdateShortcutLink(
13195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      shortcut_path, updated_properties, base::win::SHORTCUT_UPDATE_EXISTING);
1320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// {|location|, |dist|, |level|} determine |shortcut_folder|.
1323c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// For each shortcut in |shortcut_folder| that match |shortcut_filter|, apply
1324c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// |shortcut_operation|. Returns true if all operations are successful.
1325c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// All intended operations are attempted, even if failures occur.
13265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This method will abort and return false if |cancel| is non-NULL and gets set
13275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// at any point during this call.
13285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BatchShortcutAction(
13295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ShortcutFilterCallback& shortcut_filter,
13305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ShortcutOperationCallback& shortcut_operation,
13315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellUtil::ShortcutLocation location,
13325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserDistribution* dist,
13335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellUtil::ShellChange level,
13345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<ShellUtil::SharedCancellationFlag>& cancel) {
1335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!shortcut_operation.is_null());
13366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
13376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // There is no system-level Quick Launch shortcut folder.
13386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (level == ShellUtil::SYSTEM_LEVEL &&
13396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      location == ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH) {
13406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
13416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
13426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath shortcut_folder;
1344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder)) {
1345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "Cannot find path at location " << location;
13462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
13482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success = true;
1350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FileEnumerator enumerator(
1351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      shortcut_folder, false, base::FileEnumerator::FILES,
13525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16(L"*") + installer::kLnkExt);
1353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath target_path;
13545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 args;
1355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (base::FilePath shortcut_path = enumerator.Next();
1356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       !shortcut_path.empty();
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       shortcut_path = enumerator.Next()) {
13585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (cancel && cancel->data.IsSet())
13595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
1360c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (base::win::ResolveShortcut(shortcut_path, &target_path, &args)) {
1361c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      if (shortcut_filter.Run(target_path, args) &&
1362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          !shortcut_operation.Run(shortcut_path)) {
1363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        success = false;
1364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
1366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(ERROR) << "Cannot resolve shortcut at " << shortcut_path.value();
1367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      success = false;
13682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
13692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return success;
1371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// If the folder specified by {|location|, |dist|, |level|} is empty, remove it.
13753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Otherwise do nothing. Returns true on success, including the vacuous case
13763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// where no deletion occurred because directory is non-empty.
13773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool RemoveShortcutFolderIfEmpty(ShellUtil::ShortcutLocation location,
13783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 BrowserDistribution* dist,
13793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 ShellUtil::ShellChange level) {
1380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Explicitly whitelist locations, since accidental calls can be very harmful.
1381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (location != ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR &&
1382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      location != ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR &&
1383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      location != ShellUtil::SHORTCUT_LOCATION_APP_SHORTCUTS) {
1384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NOTREACHED();
1385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath shortcut_folder;
1389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder)) {
1390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "Cannot find path at location " << location;
1391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (base::IsDirectoryEmpty(shortcut_folder) &&
13943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      !base::DeleteFile(shortcut_folder, true)) {
1395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Cannot remove folder " << shortcut_folder.value();
1396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
13982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
13992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon";
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegShellPath = L"\\shell";
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command";
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegStartMenuInternet =
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"Software\\Clients\\StartMenuInternet";
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegClasses = L"Software\\Classes";
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegRegisteredApplications =
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"Software\\RegisteredApplications";
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegVistaUrlPrefs =
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"http\\UserChoice";
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kAppPathsRegistryKey =
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths";
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kAppPathsRegistryPathName = L"Path";
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const wchar_t* ShellUtil::kDefaultFileAssociations[] = {L".htm", L".html",
1419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    L".shtml", L".xht", L".xhtml", NULL};
1420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const wchar_t* ShellUtil::kPotentialFileAssociations[] = {L".htm", L".html",
1421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    L".shtml", L".xht", L".xhtml", L".webp", NULL};
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kBrowserProtocolAssociations[] = {L"ftp", L"http",
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"https", NULL};
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kPotentialProtocolAssociations[] = {L"ftp", L"http",
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"https", L"irc", L"mailto", L"mms", L"news", L"nntp", L"sms", L"smsto",
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"tel", L"urn", L"webcal", NULL};
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegUrlProtocol = L"URL Protocol";
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegApplication = L"\\Application";
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegAppUserModelId = L"AppUserModelId";
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegApplicationDescription =
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L"ApplicationDescription";
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegApplicationName = L"ApplicationName";
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegApplicationIcon = L"ApplicationIcon";
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegApplicationCompany = L"ApplicationCompany";
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegExePath = L"\\.exe";
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegVerbOpen = L"open";
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegVerbOpenNewWindow = L"opennewwindow";
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegVerbRun = L"run";
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegCommand = L"command";
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegDelegateExecute = L"DelegateExecute";
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* ShellUtil::kRegOpenWithProgids = L"OpenWithProgids";
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::QuickIsChromeRegisteredInHKLM(BrowserDistribution* dist,
14445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              const base::string16& chrome_exe,
14455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              const base::string16& suffix) {
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return QuickIsChromeRegistered(dist, chrome_exe, suffix,
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 CONFIRM_SHELL_REGISTRATION_IN_HKLM);
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ShellUtil::ShortcutLocationIsSupported(
1451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ShellUtil::ShortcutLocation location) {
1452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (location) {
1453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_DESKTOP:  // Falls through.
1454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_QUICK_LAUNCH:  // Falls through.
1455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_START_MENU_ROOT:  // Falls through.
1456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_START_MENU_CHROME_DIR:  // Falls through.
1457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:
1458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return true;
1459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SHORTCUT_LOCATION_TASKBAR_PINS:
1460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return base::win::GetVersion() >= base::win::VERSION_WIN7;
1461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SHORTCUT_LOCATION_APP_SHORTCUTS:
1462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return base::win::GetVersion() >= base::win::VERSION_WIN8;
1463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
1464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NOTREACHED();
1465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
1466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::GetShortcutPath(ShellUtil::ShortcutLocation location,
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BrowserDistribution* dist,
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ShellChange level,
14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                base::FilePath* path) {
1473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(path);
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dir_key = -1;
1475a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 folder_to_append;
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (location) {
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHORTCUT_LOCATION_DESKTOP:
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dir_key = (level == CURRENT_USER) ? base::DIR_USER_DESKTOP :
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          base::DIR_COMMON_DESKTOP;
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHORTCUT_LOCATION_QUICK_LAUNCH:
14826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // There is no support for a system-level Quick Launch shortcut.
14836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      DCHECK_EQ(level, CURRENT_USER);
14846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      dir_key = base::DIR_USER_QUICK_LAUNCH;
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_START_MENU_ROOT:
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dir_key = (level == CURRENT_USER) ? base::DIR_START_MENU :
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          base::DIR_COMMON_START_MENU;
1489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
1490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_START_MENU_CHROME_DIR:
1491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dir_key = (level == CURRENT_USER) ? base::DIR_START_MENU :
1492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                          base::DIR_COMMON_START_MENU;
1493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      folder_to_append = dist->GetStartMenuShortcutSubfolder(
1494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          BrowserDistribution::SUBFOLDER_CHROME);
1495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
1496a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:
1497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dir_key = (level == CURRENT_USER) ? base::DIR_START_MENU :
1498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                          base::DIR_COMMON_START_MENU;
1499a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      folder_to_append = dist->GetStartMenuShortcutSubfolder(
1500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          BrowserDistribution::SUBFOLDER_APPS);
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SHORTCUT_LOCATION_TASKBAR_PINS:
1503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      dir_key = base::DIR_TASKBAR_PINS;
1504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
1505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SHORTCUT_LOCATION_APP_SHORTCUTS:
1506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // TODO(huangs): Move GetAppShortcutsFolder() logic into base_paths_win.
1507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return GetAppShortcutsFolder(dist, level, path);
1508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(dir_key, path) || path->empty()) {
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << dir_key;
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1519a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!folder_to_append.empty())
1520a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    *path = path->Append(folder_to_append);
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::CreateOrUpdateShortcut(
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellUtil::ShortcutLocation location,
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserDistribution* dist,
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ShellUtil::ShortcutProperties& properties,
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellUtil::ShortcutOperation operation) {
1530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Explicitly whitelist locations to which this is applicable.
1531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (location != SHORTCUT_LOCATION_DESKTOP &&
1532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      location != SHORTCUT_LOCATION_QUICK_LAUNCH &&
1533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      location != SHORTCUT_LOCATION_START_MENU_ROOT &&
1534a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      location != SHORTCUT_LOCATION_START_MENU_CHROME_DIR &&
1535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      location != SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR) {
1536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NOTREACHED();
1537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dist);
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |pin_to_taskbar| is only acknowledged when first creating the shortcut.
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!properties.pin_to_taskbar ||
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         operation == SHELL_SHORTCUT_CREATE_ALWAYS ||
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         operation == SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL);
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath user_shortcut_path;
15472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath system_shortcut_path;
15486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (location == SHORTCUT_LOCATION_QUICK_LAUNCH) {
15496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // There is no system-level shortcut for Quick Launch.
15506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DCHECK_EQ(properties.level, CURRENT_USER);
15516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (!GetShortcutPath(
15526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 location, dist, SYSTEM_LEVEL, &system_shortcut_path)) {
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 shortcut_name(
15585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtractShortcutNameFromProperties(dist, properties));
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  system_shortcut_path = system_shortcut_path.Append(shortcut_name);
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath* chosen_path;
15622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool should_install_shortcut = true;
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (properties.level == SYSTEM_LEVEL) {
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Install the system-level shortcut if requested.
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chosen_path = &system_shortcut_path;
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (operation != SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL ||
15676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)             system_shortcut_path.empty() ||
15687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch             !base::PathExists(system_shortcut_path)) {
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Otherwise install the user-level shortcut, unless the system-level
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // variant of this shortcut is present on the machine and |operation| states
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not to create a user-level shortcut in that case.
1572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!GetShortcutPath(location, dist, CURRENT_USER, &user_shortcut_path)) {
15732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
15742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
15752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
15762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    user_shortcut_path = user_shortcut_path.Append(shortcut_name);
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chosen_path = &user_shortcut_path;
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
15792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Do not install any shortcut if we are told to install a user-level
15802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // shortcut, but the system-level variant of that shortcut is present.
15812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Other actions (e.g., pinning) can still happen with respect to the
15822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // existing system-level shortcut however.
15832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chosen_path = &system_shortcut_path;
15842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    should_install_shortcut = false;
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (chosen_path == NULL || chosen_path->empty()) {
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ShortcutOperation shortcut_operation =
15932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TranslateShortcutOperation(operation);
15942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool ret = true;
15952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (should_install_shortcut) {
15962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Make sure the parent directories exist when creating the shortcut.
15972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (shortcut_operation == base::win::SHORTCUT_CREATE_ALWAYS &&
1598a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        !base::CreateDirectory(chosen_path->DirName())) {
15992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
16002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
16012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
16022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::win::ShortcutProperties shortcut_properties(
16042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        TranslateShortcutProperties(properties));
16052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ret = base::win::CreateOrUpdateShortcutLink(
16062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *chosen_path, shortcut_properties, shortcut_operation);
16072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ret && shortcut_operation == base::win::SHORTCUT_CREATE_ALWAYS &&
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties.pin_to_taskbar &&
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::GetVersion() >= base::win::VERSION_WIN7) {
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = base::win::TaskbarPinShortcutLink(chosen_path->value().c_str());
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ret) {
16142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Failed to pin " << chosen_path->value();
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::FormatIconLocation(const base::string16& icon_path,
16225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             int icon_index) {
16235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 icon_string(icon_path);
16242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_string.append(L",");
16252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_string.append(base::IntToString16(icon_index));
16262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return icon_string;
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::GetChromeShellOpenCmd(
16305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe) {
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return L"\"" + chrome_exe + L"\" -- \"%1\"";
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::GetChromeDelegateCommand(
16355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe) {
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return L"\"" + chrome_exe + L"\" -- %*";
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShellUtil::GetRegisteredBrowsers(
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserDistribution* dist,
16415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::map<base::string16, base::string16>* browsers) {
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dist);
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(browsers);
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16 base_key(ShellUtil::kRegStartMenuInternet);
16465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 client_path;
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
16485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 name;
16495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 command;
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // HKCU has precedence over HKLM for these registrations: http://goo.gl/xjczJ.
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look in HKCU second to override any identical values found in HKLM.
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const HKEY roots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < arraysize(roots); ++i) {
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HKEY root = roots[i];
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (base::win::RegistryKeyIterator iter(root, base_key.c_str());
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         iter.Valid(); ++iter) {
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_path.assign(base_key).append(1, L'\\').append(iter.Name());
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Read the browser's name (localized according to install language).
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (key.Open(root, client_path.c_str(),
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   KEY_QUERY_VALUE) != ERROR_SUCCESS ||
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          key.ReadValue(NULL, &name) != ERROR_SUCCESS ||
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name.empty() ||
16645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          name.find(dist->GetBaseAppName()) != base::string16::npos) {
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Read the browser's reinstall command.
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (key.Open(root, (client_path + L"\\InstallInfo").c_str(),
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   KEY_QUERY_VALUE) == ERROR_SUCCESS &&
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS &&
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          !command.empty()) {
16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*browsers)[name] = command;
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::GetCurrentInstallationSuffix(
16795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserDistribution* dist,
16805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe) {
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method is somewhat the opposite of GetInstallationSpecificSuffix().
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In this case we are not trying to determine the current suffix for the
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // upcoming installation (i.e. not trying to stick to a currently bad
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // registration style if one is present).
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Here we want to determine which suffix we should use at run-time.
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In order of preference, we prefer (for user-level installs):
16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   1) Base 32 encoding of the md5 hash of the user's sid (new-style).
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   2) Username (old-style).
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   3) Unsuffixed (even worse).
16905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 tested_suffix;
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) &&
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!GetUserSpecificRegistrySuffix(&tested_suffix) ||
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix,
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                CONFIRM_PROGID_REGISTRATION)) &&
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!GetOldUserSpecificRegistrySuffix(&tested_suffix) ||
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix,
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                CONFIRM_PROGID_REGISTRATION)) &&
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix.erase(),
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               CONFIRM_PROGID_REGISTRATION)) {
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If Chrome is not registered under any of the possible suffixes (e.g.
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // tests, Canary, etc.): use the new-style suffix at run-time.
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetUserSpecificRegistrySuffix(&tested_suffix))
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return tested_suffix;
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::GetApplicationName(BrowserDistribution* dist,
17095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             const base::string16& chrome_exe) {
17105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 app_name = dist->GetBaseAppName();
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  app_name += GetCurrentInstallationSuffix(dist, chrome_exe);
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return app_name;
17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::GetBrowserModelId(BrowserDistribution* dist,
17165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            bool is_per_user_install) {
17175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 app_id(dist->GetBaseAppId());
17185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 suffix;
17192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(robertshield): Temporary hack to make the kRegisterChromeBrowserSuffix
17212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // apply to all registry values computed down in these murky depths.
17222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandLine& command_line = *CommandLine::ForCurrentProcess();
17232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_line.HasSwitch(
17242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          installer::switches::kRegisterChromeBrowserSuffix)) {
17252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    suffix = command_line.GetSwitchValueNative(
17262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        installer::switches::kRegisterChromeBrowserSuffix);
17272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (is_per_user_install && !GetUserSpecificRegistrySuffix(&suffix)) {
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is only one component (i.e. the suffixed appid) in this case, but it
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is still necessary to go through the appid constructor to make sure the
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned appid is truncated if necessary.
17335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<base::string16> components(1, app_id.append(suffix));
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return BuildAppModelId(components);
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::BuildAppModelId(
17385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<base::string16>& components) {
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(components.size(), 0U);
17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the maximum numbers of characters allowed in each component
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (accounting for the dots added between each component).
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t available_chars =
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      installer::kMaxAppModelIdLength - (components.size() - 1);
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t max_component_length = available_chars / components.size();
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |max_component_length| should be at least 2; otherwise the truncation logic
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // below breaks.
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (max_component_length < 2U) {
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (*components.begin()).substr(0, installer::kMaxAppModelIdLength);
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 app_id;
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  app_id.reserve(installer::kMaxAppModelIdLength);
17565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<base::string16>::const_iterator it = components.begin();
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != components.end(); ++it) {
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != components.begin())
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_id.push_back(L'.');
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& component = *it;
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!component.empty());
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (component.length() > max_component_length) {
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Append a shortened version of this component. Cut in the middle to try
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // to avoid losing the unique parts of this component (which are usually
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // at the beginning or end for things like usernames and paths).
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_id.append(component.c_str(), 0, max_component_length / 2);
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_id.append(component.c_str(),
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    component.length() - ((max_component_length + 1) / 2),
17705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    base::string16::npos);
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_id.append(component);
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No spaces are allowed in the AppUserModelId according to MSDN.
1776cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::ReplaceChars(app_id, base::ASCIIToUTF16(" "), base::ASCIIToUTF16("_"),
1777cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     &app_id);
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return app_id;
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellUtil::DefaultState ShellUtil::GetChromeDefaultState() {
1782a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::FilePath app_path;
1783a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &app_path)) {
1784a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NOTREACHED();
1785a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return ShellUtil::UNKNOWN_DEFAULT;
1786a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1787a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1788a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return GetChromeDefaultStateFromPath(app_path);
1789a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
1790a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1791a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ShellUtil::DefaultState ShellUtil::GetChromeDefaultStateFromPath(
1792a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::FilePath& chrome_exe) {
17931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
17941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (distribution->GetDefaultBrowserControlPolicy() ==
17951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
179668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return NOT_DEFAULT;
17971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When we check for default browser we don't necessarily want to count file
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // type handlers and icons as having changed the default browser status,
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since the user may have changed their shell settings to cause HTML files
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to open with a text editor for example. We also don't want to aggressively
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // claim FTP, since the user may have a separate FTP client. It is an open
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // question as to how to "heal" these settings. Perhaps the user should just
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // re-run the installer or run with the --set-default-browser command line
18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // flag. There is doubtless some other key we can hook into to cause "Repair"
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to show up in Add/Remove programs for us.
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const wchar_t* const kChromeProtocols[] = { L"http", L"https" };
1808a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return ProbeProtocolHandlers(chrome_exe,
1809a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               kChromeProtocols,
1810a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               arraysize(kChromeProtocols));
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellUtil::DefaultState ShellUtil::GetChromeDefaultProtocolClientState(
18145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& protocol) {
18151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
18161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (distribution->GetDefaultBrowserControlPolicy() ==
18171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
181868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return NOT_DEFAULT;
18191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
18201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (protocol.empty())
18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return UNKNOWN_DEFAULT;
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1824a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::FilePath chrome_exe;
1825a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
1826a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NOTREACHED();
1827a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return ShellUtil::UNKNOWN_DEFAULT;
1828a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1829a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const wchar_t* const protocols[] = { protocol.c_str() };
1831a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return ProbeProtocolHandlers(chrome_exe,
1832a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               protocols,
1833a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               arraysize(protocols));
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::CanMakeChromeDefaultUnattended() {
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::win::GetVersion() < base::win::VERSION_WIN8;
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int shell_change,
18435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  const base::string16& chrome_exe,
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  bool elevate_if_not_admin) {
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!(shell_change & ShellUtil::SYSTEM_LEVEL) || IsUserAnAdmin());
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
18481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (distribution->GetDefaultBrowserControlPolicy() !=
18491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
18511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Windows 8 does not permit making a browser default just like that.
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This process needs to be routed through the system's UI. Use
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ShowMakeChromeDefaultSystemUI instead (below).
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CanMakeChromeDefaultUnattended()) {
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShellUtil::RegisterChromeBrowser(
18615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           dist, chrome_exe, base::string16(), elevate_if_not_admin)) {
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ret = true;
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First use the new "recommended" way on Vista to make Chrome default
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // browser.
18685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 app_name = GetApplicationName(dist, chrome_exe);
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Windows Vista and Win7 we still can set ourselves via the
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the IApplicationAssociationRegistration interface.
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Registering Chrome as default browser on Vista.";
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::ScopedComPtr<IApplicationAssociationRegistration> pAAR;
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = pAAR.CreateInstance(CLSID_ApplicationAssociationRegistration,
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL, CLSCTX_INPROC);
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SUCCEEDED(hr)) {
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = pAAR->SetAppAsDefault(app_name.c_str(),
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ShellUtil::kBrowserProtocolAssociations[i], AT_URLPROTOCOL);
18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SUCCEEDED(hr)) {
18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ret = false;
18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          LOG(ERROR) << "Failed to register as default for protocol "
18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << ShellUtil::kBrowserProtocolAssociations[i]
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << " (" << hr << ")";
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = pAAR->SetAppAsDefault(app_name.c_str(),
1891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            ShellUtil::kDefaultFileAssociations[i], AT_FILEEXTENSION);
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SUCCEEDED(hr)) {
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ret = false;
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          LOG(ERROR) << "Failed to register as default for file extension "
1895c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     << ShellUtil::kDefaultFileAssociations[i]
1896c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     << " (" << hr << ")";
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!RegisterChromeAsDefaultXPStyle(dist, shell_change, chrome_exe))
19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = false;
19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send Windows notification event so that it can update icons for
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // file associations.
19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShellUtil::ShowMakeChromeDefaultSystemUI(
19125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserDistribution* dist,
19135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe) {
19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
19151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (dist->GetDefaultBrowserControlPolicy() !=
19161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
19181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!RegisterChromeBrowser(dist, chrome_exe, base::string16(), true))
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool succeeded = true;
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_default = (GetChromeDefaultState() == IS_DEFAULT);
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_default) {
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Windows 8, you can't set yourself as the default handler
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // programatically. In other words IApplicationAssociationRegistration
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has been rendered useless. What you can do is to launch
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // "Set Program Associations" section of the "Default Programs"
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // control panel, which is a mess, or pop the concise "How you want to open
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // webpages?" dialog.  We choose the latter.
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    succeeded = LaunchSelectDefaultProtocolHandlerDialog(L"http");
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_default = (succeeded && GetChromeDefaultState() == IS_DEFAULT);
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (succeeded && is_default)
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegisterChromeAsDefaultXPStyle(dist, CURRENT_USER, chrome_exe);
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return succeeded;
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShellUtil::MakeChromeDefaultProtocolClient(
19415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserDistribution* dist,
19425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe,
19435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& protocol) {
19441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (dist->GetDefaultBrowserControlPolicy() !=
19451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
19471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!RegisterChromeForProtocol(
19505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           dist, chrome_exe, base::string16(), protocol, true))
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Windows 8 does not permit making a browser default just like that.
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This process needs to be routed through the system's UI. Use
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ShowMakeChromeDefaultProocolClientSystemUI instead (below).
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CanMakeChromeDefaultUnattended())
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ret = true;
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First use the new "recommended" way on Vista to make Chrome default
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // protocol handler.
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Registering Chrome as default handler for " << protocol
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << " on Vista.";
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::ScopedComPtr<IApplicationAssociationRegistration> pAAR;
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = pAAR.CreateInstance(CLSID_ApplicationAssociationRegistration,
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, CLSCTX_INPROC);
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SUCCEEDED(hr)) {
19695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 app_name = GetApplicationName(dist, chrome_exe);
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hr = pAAR->SetAppAsDefault(app_name.c_str(), protocol.c_str(),
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 AT_URLPROTOCOL);
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!SUCCEEDED(hr)) {
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = false;
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Could not make Chrome default protocol client (Vista):"
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " HRESULT=" << hr << ".";
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now use the old way to associate Chrome with the desired protocol. This
19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should not be required on Vista+, but since some applications still read
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Software\Classes\<protocol> key directly, do this on Vista+ also.
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!RegisterChromeAsDefaultProtocolClientXPStyle(dist, chrome_exe, protocol))
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = false;
19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::ShowMakeChromeDefaultProtocolClientSystemUI(
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserDistribution* dist,
19915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& chrome_exe,
19925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& protocol) {
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
19941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (dist->GetDefaultBrowserControlPolicy() !=
19951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
19971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!RegisterChromeForProtocol(
20005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           dist, chrome_exe, base::string16(), protocol, true))
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool succeeded = true;
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_default = (
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetChromeDefaultProtocolClientState(protocol) == IS_DEFAULT);
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_default) {
20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Windows 8, you can't set yourself as the default handler
20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // programatically. In other words IApplicationAssociationRegistration
20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has been rendered useless. What you can do is to launch
20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // "Set Program Associations" section of the "Default Programs"
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // control panel, which is a mess, or pop the concise "How you want to open
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // links of this type (protocol)?" dialog.  We choose the latter.
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    succeeded = LaunchSelectDefaultProtocolHandlerDialog(protocol.c_str());
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_default = (succeeded &&
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  GetChromeDefaultProtocolClientState(protocol) == IS_DEFAULT);
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (succeeded && is_default)
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegisterChromeAsDefaultProtocolClientXPStyle(dist, chrome_exe, protocol);
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return succeeded;
20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::RegisterChromeBrowser(BrowserDistribution* dist,
20235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const base::string16& chrome_exe,
20245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const base::string16& unique_suffix,
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool elevate_if_not_admin) {
20261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (dist->GetDefaultBrowserControlPolicy() ==
20271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
20291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandLine& command_line = *CommandLine::ForCurrentProcess();
20322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 suffix;
20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!unique_suffix.empty()) {
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suffix = unique_suffix;
20362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (command_line.HasSwitch(
20372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 installer::switches::kRegisterChromeBrowserSuffix)) {
20382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    suffix = command_line.GetSwitchValueNative(
20392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        installer::switches::kRegisterChromeBrowserSuffix);
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!GetInstallationSpecificSuffix(dist, chrome_exe, &suffix)) {
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveRunVerbOnWindows8(dist, chrome_exe);
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool user_level = InstallUtil::IsPerUserInstall(chrome_exe.c_str());
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HKEY root = DetermineRegistrationRoot(user_level);
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Look only in HKLM for system-level installs (otherwise, if a user-level
20502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // install is also present, it will lead IsChromeRegistered() to think this
20512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // system-level install isn't registered properly as it is shadowed by the
20522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // user-level install's registrations).
20532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32 look_for_in = user_level ?
20542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RegistryEntry::LOOK_IN_HKCU_THEN_HKLM : RegistryEntry::LOOK_IN_HKLM;
20552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if chrome is already registered with this suffix.
20572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in))
20582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
20592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = true;
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) {
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Do the full registration if we can do it at user-level or if the user is
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // an admin.
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedVector<RegistryEntry> progid_and_appreg_entries;
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedVector<RegistryEntry> shell_entries;
20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix,
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &progid_and_appreg_entries);
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix,
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             &progid_and_appreg_entries);
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegistryEntry::GetShellIntegrationEntries(
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dist, chrome_exe, suffix, &shell_entries);
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = (AddRegistryEntries(root, progid_and_appreg_entries) &&
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              AddRegistryEntries(root, shell_entries));
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (elevate_if_not_admin &&
2075cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::win::GetVersion() >= base::win::VERSION_VISTA &&
2076cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) {
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the user is not an admin and OS is between Vista and Windows 7
20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // inclusively, try to elevate and register. This is only intended for
20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // user-level installs as system-level installs should always be run with
20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // admin rights.
20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = true;
20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we got to this point then all we can do is create ProgId and basic app
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // registrations under HKCU.
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedVector<RegistryEntry> entries;
20865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RegistryEntry::GetProgIdEntries(
20875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dist, chrome_exe, base::string16(), &entries);
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prefer to use |suffix|; unless Chrome's ProgIds are already registered
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with no suffix (as per the old registration style): in which case some
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other registry entries could refer to them and since we were not able to
20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // set our HKLM entries above, we are better off not altering these here.
20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) {
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!suffix.empty()) {
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        entries.clear();
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries);
20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries);
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = AddRegistryEntries(HKEY_CURRENT_USER, entries);
20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The ProgId is registered unsuffixed in HKCU, also register the app with
21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Windows in HKCU (this was not done in the old registration style and
21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // thus needs to be done after the above check for the unsuffixed
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // registration).
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries.clear();
21055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RegistryEntry::GetAppRegistrationEntries(chrome_exe, base::string16(),
21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &entries);
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = AddRegistryEntries(HKEY_CURRENT_USER, entries);
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist,
21155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          const base::string16& chrome_exe,
21165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          const base::string16& unique_suffix,
21175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          const base::string16& protocol,
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          bool elevate_if_not_admin) {
21191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (dist->GetDefaultBrowserControlPolicy() ==
21201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 suffix;
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!unique_suffix.empty()) {
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suffix = unique_suffix;
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!GetInstallationSpecificSuffix(dist, chrome_exe, &suffix)) {
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool user_level = InstallUtil::IsPerUserInstall(chrome_exe.c_str());
21322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HKEY root = DetermineRegistrationRoot(user_level);
21332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Look only in HKLM for system-level installs (otherwise, if a user-level
21352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // install is also present, it could lead IsChromeRegisteredForProtocol() to
21362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // think this system-level install isn't registered properly as it may be
21372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // shadowed by the user-level install's registrations).
21382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32 look_for_in = user_level ?
21392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RegistryEntry::LOOK_IN_HKCU_THEN_HKLM : RegistryEntry::LOOK_IN_HKLM;
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if chrome is already registered with this suffix.
21422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsChromeRegisteredForProtocol(dist, suffix, protocol, look_for_in))
21432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) {
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can do this operation directly.
21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // First, make sure Chrome is fully registered on this machine.
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!RegisterChromeBrowser(dist, chrome_exe, suffix, false))
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Write in the capabillity for the protocol.
21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedVector<RegistryEntry> entries;
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegistryEntry::GetProtocolCapabilityEntries(dist, suffix, protocol,
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &entries);
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return AddRegistryEntries(root, entries);
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (elevate_if_not_admin &&
21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             base::win::GetVersion() >= base::win::VERSION_VISTA) {
21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Elevate to do the whole job
21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ElevateAndRegisterChrome(dist, chrome_exe, suffix, protocol);
21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Admin rights are required to register capabilities before Windows 8.
21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
2167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ShellUtil::RemoveShortcuts(ShellUtil::ShortcutLocation location,
2168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                BrowserDistribution* dist,
2169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                ShellChange level,
2170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                const base::FilePath& target_exe) {
2171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!ShellUtil::ShortcutLocationIsSupported(location))
2172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;  // Vacuous success.
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
217458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  FilterTargetEq shortcut_filter(target_exe, false);
21753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Main operation to apply to each shortcut in the directory specified.
21763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ShortcutOperationCallback shortcut_operation(
21773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      location == SHORTCUT_LOCATION_TASKBAR_PINS ?
21783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          base::Bind(&ShortcutOpUnpin) : base::Bind(&ShortcutOpDelete));
21793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool success = BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
21805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     shortcut_operation, location, dist, level,
21815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL);
21823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Remove chrome-specific shortcut folders if they are now empty.
21833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (success &&
2184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      (location == SHORTCUT_LOCATION_START_MENU_CHROME_DIR ||
2185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       location == SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR ||
21863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       location == SHORTCUT_LOCATION_APP_SHORTCUTS)) {
21873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    success = RemoveShortcutFolderIfEmpty(location, dist, level);
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return success;
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
21935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShellUtil::RetargetShortcutsWithArgs(
2194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ShellUtil::ShortcutLocation location,
2195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserDistribution* dist,
2196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ShellChange level,
21975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& old_target_exe,
21985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& new_target_exe) {
2199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!ShellUtil::ShortcutLocationIsSupported(location))
2200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;  // Vacuous success.
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FilterTargetEq shortcut_filter(old_target_exe, true);
22035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShortcutOperationCallback shortcut_operation(
22045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&ShortcutOpRetarget, old_target_exe, new_target_exe));
22055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
22065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             shortcut_operation, location, dist, level, NULL);
22075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
22085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
22095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
22105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
22115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellUtil::ShortcutLocation location,
22125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserDistribution* dist,
22135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShellChange level,
22145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& chrome_exe,
22155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool do_removal,
22165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<SharedCancellationFlag>& cancel,
22175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::pair<base::FilePath, base::string16> >* shortcuts) {
22185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ShellUtil::ShortcutLocationIsSupported(location))
22195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
22205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(dist);
22215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FilterTargetEq shortcut_filter(chrome_exe, true);
22223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ShortcutOperationCallback shortcut_operation(
22235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&ShortcutOpListOrRemoveUnknownArgs, do_removal, shortcuts));
22243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
22255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             shortcut_operation, location, dist, level, cancel);
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShellUtil::GetUserSpecificRegistrySuffix(base::string16* suffix) {
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use a thread-safe cache for the user's suffix.
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static base::LazyInstance<UserSpecificRegistrySuffix>::Leaky suffix_instance =
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LAZY_INSTANCE_INITIALIZER;
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return suffix_instance.Get().GetSuffix(suffix);
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShellUtil::GetOldUserSpecificRegistrySuffix(base::string16* suffix) {
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t user_name[256];
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD size = arraysize(user_name);
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::GetUserName(user_name, &size) == 0 || size < 1) {
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix->reserve(size);
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix->assign(1, L'.');
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suffix->append(user_name, size - 1);
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellUtil::ByteArrayToBase32(const uint8* bytes, size_t size) {
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Eliminate special cases first.
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size == 0) {
22535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16();
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (size == 1) {
22555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 ret;
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret.push_back(kEncoding[(bytes[0] & 0xf8) >> 3]);
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret.push_back(kEncoding[(bytes[0] & 0x07) << 2]);
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret;
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (size >= std::numeric_limits<size_t>::max() / 8) {
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If |size| is too big, the calculation of |encoded_length| below will
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // overflow.
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
22635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16();
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overestimate the number of bits in the string by 4 so that dividing by 5
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is the equivalent of rounding up the actual number of bits divided by 5.
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t encoded_length = (size * 8 + 4) / 5;
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 ret;
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret.reserve(encoded_length);
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A bit stream which will be read from the left and appended to from the
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // right as it's emptied.
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 bit_stream = (bytes[0] << 8) + bytes[1];
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t next_byte_index = 2;
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int free_bits = 0;
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (free_bits < 16) {
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Extract the 5 leftmost bits in the stream
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret.push_back(kEncoding[(bit_stream & 0xf800) >> 11]);
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bit_stream <<= 5;
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free_bits += 5;
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is enough room in the bit stream, inject another byte (if there
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // are any left...).
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (free_bits >= 8 && next_byte_index < size) {
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      free_bits -= 8;
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bit_stream += bytes[next_byte_index++] << free_bits;
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(ret.length(), encoded_length);
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295