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, ¤t_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