OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file defines functions that integrate Chrome in Windows shell. These | 5 // This file defines functions that integrate Chrome in Windows shell. These |
6 // functions can be used by Chrome as well as Chrome installer. All of the | 6 // functions can be used by Chrome as well as Chrome installer. All of the |
7 // work is done by the local functions defined in anonymous namespace in | 7 // work is done by the local functions defined in anonymous namespace in |
8 // this class. | 8 // this class. |
9 | 9 |
10 #include "chrome/installer/util/shell_util.h" | 10 #include "chrome/installer/util/shell_util.h" |
11 | 11 |
12 #include <windows.h> | 12 #include <windows.h> |
13 #include <shlobj.h> | 13 #include <shlobj.h> |
14 #include <shobjidl.h> | 14 #include <shobjidl.h> |
15 | 15 |
16 #include <algorithm> | 16 #include <algorithm> |
17 #include <iterator> | 17 #include <iterator> |
18 #include <limits> | 18 #include <limits> |
19 #include <memory> | 19 #include <memory> |
20 #include <string> | 20 #include <string> |
21 #include <utility> | 21 #include <utility> |
22 | 22 |
23 #include "base/bind.h" | 23 #include "base/bind.h" |
| 24 #include "base/callback_helpers.h" |
24 #include "base/command_line.h" | 25 #include "base/command_line.h" |
25 #include "base/files/file_enumerator.h" | 26 #include "base/files/file_enumerator.h" |
26 #include "base/files/file_path.h" | 27 #include "base/files/file_path.h" |
27 #include "base/files/file_util.h" | 28 #include "base/files/file_util.h" |
28 #include "base/lazy_instance.h" | 29 #include "base/lazy_instance.h" |
29 #include "base/logging.h" | 30 #include "base/logging.h" |
30 #include "base/macros.h" | 31 #include "base/macros.h" |
31 #include "base/md5.h" | 32 #include "base/md5.h" |
32 #include "base/memory/ptr_util.h" | 33 #include "base/memory/ptr_util.h" |
33 #include "base/metrics/histogram_macros.h" | 34 #include "base/metrics/histogram_macros.h" |
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 uint32_t look_for_in) { | 676 uint32_t look_for_in) { |
676 std::vector<std::unique_ptr<RegistryEntry>> entries; | 677 std::vector<std::unique_ptr<RegistryEntry>> entries; |
677 GetProtocolCapabilityEntries(suffix, protocol, &entries); | 678 GetProtocolCapabilityEntries(suffix, protocol, &entries); |
678 return AreEntriesAsDesired(entries, look_for_in); | 679 return AreEntriesAsDesired(entries, look_for_in); |
679 } | 680 } |
680 | 681 |
681 // This method registers Chrome by launching an elevated setup.exe. That will | 682 // This method registers Chrome by launching an elevated setup.exe. That will |
682 // show the user the standard elevation prompt. If the user accepts it the new | 683 // show the user the standard elevation prompt. If the user accepts it the new |
683 // process will make the necessary changes and return SUCCESS that we capture | 684 // process will make the necessary changes and return SUCCESS that we capture |
684 // and return. If protocol is non-empty we will also register Chrome as being | 685 // and return. If protocol is non-empty we will also register Chrome as being |
685 // capable of handling the protocol. This is most commonly used on per-user | 686 // capable of handling the protocol. This is used for general browser |
686 // installs on Windows 7 where setup.exe did not have permission to register | 687 // registration on Windows 7 for per-user installs where setup.exe did not have |
687 // Chrome during install. It may also be used on all OSs for system-level | 688 // permission to register Chrome during install. It may also be used on Windows |
688 // installs in case Chrome's registration is somehow broken or missing. | 689 // 7 for system-level installs to register Chrome for a specific protocol. |
689 bool ElevateAndRegisterChrome(BrowserDistribution* dist, | 690 bool ElevateAndRegisterChrome(BrowserDistribution* dist, |
690 const base::FilePath& chrome_exe, | 691 const base::FilePath& chrome_exe, |
691 const base::string16& suffix, | 692 const base::string16& suffix, |
692 const base::string16& protocol) { | 693 const base::string16& protocol) { |
693 // Check for setup.exe in the same directory as chrome.exe, as is the case | 694 // Check for setup.exe in the same directory as chrome.exe, as is the case |
694 // when running out of a build output directory. | 695 // when running out of a build output directory. |
695 base::FilePath exe_path = chrome_exe.DirName().Append(installer::kSetupExe); | 696 base::FilePath exe_path = chrome_exe.DirName().Append(installer::kSetupExe); |
696 | 697 |
697 // Failing that, read the path to setup.exe from Chrome's ClientState key, | 698 // Failing that, read the path to setup.exe from Chrome's ClientState key, |
698 // which is the canonical location of the installer for all types of installs | 699 // which is the canonical location of the installer for all types of installs |
(...skipping 1383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2082 // install is also present, it will lead IsChromeRegistered() to think this | 2083 // install is also present, it will lead IsChromeRegistered() to think this |
2083 // system-level install isn't registered properly as it is shadowed by the | 2084 // system-level install isn't registered properly as it is shadowed by the |
2084 // user-level install's registrations). | 2085 // user-level install's registrations). |
2085 uint32_t look_for_in = user_level ? RegistryEntry::LOOK_IN_HKCU_THEN_HKLM | 2086 uint32_t look_for_in = user_level ? RegistryEntry::LOOK_IN_HKCU_THEN_HKLM |
2086 : RegistryEntry::LOOK_IN_HKLM; | 2087 : RegistryEntry::LOOK_IN_HKLM; |
2087 | 2088 |
2088 // Check if chrome is already registered with this suffix. | 2089 // Check if chrome is already registered with this suffix. |
2089 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) | 2090 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) |
2090 return true; | 2091 return true; |
2091 | 2092 |
2092 bool result = true; | 2093 // Ensure that the shell is notified of the mutations below. Specific exit |
| 2094 // points may disable this if no mutations are made. |
| 2095 base::ScopedClosureRunner notify_on_exit(base::Bind([] { |
| 2096 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); |
| 2097 })); |
| 2098 |
| 2099 // Do the full registration at user-level or if the user is an admin. |
2093 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { | 2100 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { |
2094 // Do the full registration if we can do it at user-level or if the user is | |
2095 // an admin. | |
2096 std::vector<std::unique_ptr<RegistryEntry>> progid_and_appreg_entries; | 2101 std::vector<std::unique_ptr<RegistryEntry>> progid_and_appreg_entries; |
2097 std::vector<std::unique_ptr<RegistryEntry>> shell_entries; | 2102 std::vector<std::unique_ptr<RegistryEntry>> shell_entries; |
2098 GetChromeProgIdEntries(dist, chrome_exe, suffix, | 2103 GetChromeProgIdEntries(dist, chrome_exe, suffix, |
2099 &progid_and_appreg_entries); | 2104 &progid_and_appreg_entries); |
2100 GetChromeAppRegistrationEntries(chrome_exe, suffix, | 2105 GetChromeAppRegistrationEntries(chrome_exe, suffix, |
2101 &progid_and_appreg_entries); | 2106 &progid_and_appreg_entries); |
2102 GetShellIntegrationEntries(dist, chrome_exe, suffix, &shell_entries); | 2107 GetShellIntegrationEntries(dist, chrome_exe, suffix, &shell_entries); |
2103 result = (AddRegistryEntries(root, progid_and_appreg_entries) && | 2108 return AddRegistryEntries(root, progid_and_appreg_entries) && |
2104 AddRegistryEntries(root, shell_entries)); | 2109 AddRegistryEntries(root, shell_entries); |
2105 } else if (elevate_if_not_admin && | 2110 } |
2106 base::win::GetVersion() >= base::win::VERSION_VISTA && | 2111 // The installer is responsible for registration for system-level installs, so |
| 2112 // never try to do it here. Getting to this point for a system-level install |
| 2113 // likely means that IsChromeRegistered thinks registration is broken due to |
| 2114 // localization issues (see https://crbug.com/717913#c18). It likely is not, |
| 2115 // so return success to allow Chrome to be made default. |
| 2116 if (!user_level) { |
| 2117 notify_on_exit.Release().Reset(); |
| 2118 return true; |
| 2119 } |
| 2120 // Try to elevate and register if requested for per-user installs if the user |
| 2121 // is not an admin. |
| 2122 if (elevate_if_not_admin && |
2107 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { | 2123 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { |
2108 // If the user is not an admin and OS is between Vista and Windows 7 | 2124 return true; |
2109 // inclusively, try to elevate and register. This is only intended for | 2125 } |
2110 // user-level installs as system-level installs should always be run with | 2126 // If we got to this point then all we can do is create ProgId and basic app |
2111 // admin rights. | 2127 // registrations under HKCU. |
2112 result = true; | 2128 std::vector<std::unique_ptr<RegistryEntry>> entries; |
2113 } else { | 2129 GetChromeProgIdEntries(dist, chrome_exe, base::string16(), &entries); |
2114 // If we got to this point then all we can do is create ProgId and basic app | 2130 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered with |
2115 // registrations under HKCU. | 2131 // no suffix (as per the old registration style): in which case some other |
2116 std::vector<std::unique_ptr<RegistryEntry>> entries; | 2132 // registry entries could refer to them and since we were not able to set our |
2117 GetChromeProgIdEntries(dist, chrome_exe, base::string16(), &entries); | 2133 // HKLM entries above, we are better off not altering these here. |
2118 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered | 2134 if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) { |
2119 // with no suffix (as per the old registration style): in which case some | 2135 if (!suffix.empty()) { |
2120 // other registry entries could refer to them and since we were not able to | |
2121 // set our HKLM entries above, we are better off not altering these here. | |
2122 if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) { | |
2123 if (!suffix.empty()) { | |
2124 entries.clear(); | |
2125 GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); | |
2126 GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); | |
2127 } | |
2128 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | |
2129 } else { | |
2130 // The ProgId is registered unsuffixed in HKCU, also register the app with | |
2131 // Windows in HKCU (this was not done in the old registration style and | |
2132 // thus needs to be done after the above check for the unsuffixed | |
2133 // registration). | |
2134 entries.clear(); | 2136 entries.clear(); |
2135 GetChromeAppRegistrationEntries(chrome_exe, base::string16(), &entries); | 2137 GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); |
2136 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | 2138 GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); |
2137 } | 2139 } |
| 2140 return AddRegistryEntries(HKEY_CURRENT_USER, entries); |
2138 } | 2141 } |
2139 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 2142 // The ProgId is registered unsuffixed in HKCU, also register the app with |
2140 return result; | 2143 // Windows in HKCU (this was not done in the old registration style and thus |
| 2144 // needs to be done after the above check for the unsuffixed registration). |
| 2145 entries.clear(); |
| 2146 GetChromeAppRegistrationEntries(chrome_exe, base::string16(), &entries); |
| 2147 return AddRegistryEntries(HKEY_CURRENT_USER, entries); |
2141 } | 2148 } |
2142 | 2149 |
2143 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, | 2150 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, |
2144 const base::FilePath& chrome_exe, | 2151 const base::FilePath& chrome_exe, |
2145 const base::string16& unique_suffix, | 2152 const base::string16& unique_suffix, |
2146 const base::string16& protocol, | 2153 const base::string16& protocol, |
2147 bool elevate_if_not_admin) { | 2154 bool elevate_if_not_admin) { |
2148 // Assert that this is only called with the one relevant distribution. | 2155 // Assert that this is only called with the one relevant distribution. |
2149 // TODO(grt): Remove this when BrowserDistribution goes away. | 2156 // TODO(grt): Remove this when BrowserDistribution goes away. |
2150 DCHECK_EQ(BrowserDistribution::GetDistribution(), dist); | 2157 DCHECK_EQ(BrowserDistribution::GetDistribution(), dist); |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2344 for (const auto& entry : entries) | 2351 for (const auto& entry : entries) |
2345 entry->AddToWorkItemList(root, items.get()); | 2352 entry->AddToWorkItemList(root, items.get()); |
2346 | 2353 |
2347 // Apply all the registry changes and if there is a problem, rollback | 2354 // Apply all the registry changes and if there is a problem, rollback |
2348 if (!items->Do()) { | 2355 if (!items->Do()) { |
2349 items->Rollback(); | 2356 items->Rollback(); |
2350 return false; | 2357 return false; |
2351 } | 2358 } |
2352 return true; | 2359 return true; |
2353 } | 2360 } |
OLD | NEW |