Chromium Code Reviews| 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 | 14 |
| 15 #include <limits> | |
| 15 #include <list> | 16 #include <list> |
| 16 | 17 |
| 17 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 18 #include "base/file_path.h" | 19 #include "base/file_path.h" |
| 19 #include "base/file_util.h" | 20 #include "base/file_util.h" |
| 21 #include "base/lazy_instance.h" | |
| 20 #include "base/logging.h" | 22 #include "base/logging.h" |
| 23 #include "base/md5.h" | |
| 21 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/scoped_ptr.h" |
| 22 #include "base/path_service.h" | 25 #include "base/path_service.h" |
| 23 #include "base/stl_util.h" | 26 #include "base/stl_util.h" |
| 24 #include "base/string_number_conversions.h" | 27 #include "base/string_number_conversions.h" |
| 25 #include "base/string_split.h" | 28 #include "base/string_split.h" |
| 26 #include "base/string_util.h" | 29 #include "base/string_util.h" |
| 27 #include "base/utf_string_conversions.h" | 30 #include "base/utf_string_conversions.h" |
| 28 #include "base/values.h" | 31 #include "base/values.h" |
| 29 #include "base/win/registry.h" | 32 #include "base/win/registry.h" |
| 30 #include "base/win/scoped_comptr.h" | 33 #include "base/win/scoped_comptr.h" |
| 34 #include "base/win/win_util.h" | |
| 31 #include "base/win/windows_version.h" | 35 #include "base/win/windows_version.h" |
| 32 #include "chrome/common/chrome_constants.h" | 36 #include "chrome/common/chrome_constants.h" |
| 33 #include "chrome/common/chrome_switches.h" | 37 #include "chrome/common/chrome_switches.h" |
| 34 #include "chrome/installer/util/browser_distribution.h" | 38 #include "chrome/installer/util/browser_distribution.h" |
| 35 #include "chrome/installer/util/install_util.h" | 39 #include "chrome/installer/util/install_util.h" |
| 36 #include "chrome/installer/util/master_preferences.h" | 40 #include "chrome/installer/util/master_preferences.h" |
| 37 #include "chrome/installer/util/master_preferences_constants.h" | 41 #include "chrome/installer/util/master_preferences_constants.h" |
| 38 | 42 |
| 39 using base::win::RegKey; | 43 using base::win::RegKey; |
| 40 | 44 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 78 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); | 82 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); |
| 79 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); | 83 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); |
| 80 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); | 84 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); |
| 81 | 85 |
| 82 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | | 86 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | |
| 83 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; | 87 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; |
| 84 | 88 |
| 85 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; | 89 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; |
| 86 } | 90 } |
| 87 | 91 |
| 92 // Returns the current (or installed) browser's ProgId (e.g. | |
| 93 // "ChromeHTML|suffix|"). | |
| 94 // |suffix| can be the empty string. | |
| 95 string16 GetBrowserProgId(const string16& suffix) { | |
| 96 string16 chrome_html(ShellUtil::kChromeHTMLProgId); | |
| 97 chrome_html.append(suffix); | |
| 98 | |
| 99 // ProgIds cannot be longer than 39 characters. | |
| 100 // Ref: http://msdn.microsoft.com/en-us/library/aa911706.aspx. | |
| 101 // Make all new registrations comply with this requirement (existing | |
| 102 // registrations must be preserved). | |
| 103 string16 new_style_suffix; | |
| 104 if (ShellUtil::GetUserSpecificRegistrySuffix(&new_style_suffix) && | |
| 105 suffix == new_style_suffix && chrome_html.length() > 39) { | |
| 106 NOTREACHED(); | |
| 107 chrome_html.erase(39); | |
| 108 } | |
| 109 return chrome_html; | |
| 110 } | |
| 111 | |
| 112 // This class is used to initialize and cache a base 32 encoding of the md5 hash | |
| 113 // of this user's username preceded by a dot. | |
| 114 // This is guaranteed to be unique on the machine and 27 characters long | |
| 115 // (including the '.'). | |
| 116 // This is then meant to be used as a suffix on all registrations that may | |
| 117 // conflict with another user-level Chrome install. | |
| 118 class UserSpecificRegistrySuffix { | |
| 119 public: | |
| 120 UserSpecificRegistrySuffix() { | |
|
grt (UTC plus 2)
2012/07/05 20:00:19
style dictates not inlining like this even though
gab
2012/07/05 21:19:53
Oh interesting, I didn't know the compiler interpr
| |
| 121 // Do all the initialization in the constructor to be able to build the | |
| 122 // suffix in a thread-safe manner when used in conjunction with a | |
| 123 // LazyInstance. | |
| 124 wchar_t user_name[256]; | |
| 125 DWORD size = arraysize(user_name); | |
| 126 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
| 127 NOTREACHED(); | |
| 128 return; | |
| 129 } | |
| 130 COMPILE_ASSERT(sizeof(base::MD5Digest) == 16, size_of_MD5_not_as_expected_); | |
| 131 base::MD5Digest md5_digest; | |
| 132 base::MD5Sum(user_name, size, &md5_digest); | |
|
grt (UTC plus 2)
2012/07/05 20:00:19
this includes the string terminator in the hash.
gab
2012/07/05 21:19:53
Changed to sid string.
| |
| 133 const string16 base32_md5( | |
| 134 ShellUtil::ByteArrayToBase32(md5_digest.a, arraysize(md5_digest.a))); | |
| 135 // The value returned by the base32 algorithm above must never change and | |
| 136 // must always be 26 characters long (i.e. if someone ever moves this to | |
| 137 // base and implements the full base32 algorithm (i.e. with appended '=' | |
| 138 // signs in the output), they must provide a flag to allow this method to | |
| 139 // still request the output with no appended '=' signs). | |
| 140 DCHECK_EQ(base32_md5.length(), 26U); | |
| 141 suffix_.reserve(base32_md5.length() + 1); | |
| 142 suffix_.assign(1, L'.'); | |
| 143 suffix_.append(base32_md5); | |
| 144 } | |
| 145 | |
| 146 bool GetSuffix(string16* suffix) { | |
| 147 if (suffix_.empty()) { | |
| 148 NOTREACHED(); | |
| 149 return false; | |
| 150 } | |
| 151 suffix->assign(suffix_); | |
| 152 return true; | |
| 153 } | |
| 154 | |
| 155 private: | |
| 156 string16 suffix_; | |
| 157 | |
| 158 DISALLOW_COPY_AND_ASSIGN(UserSpecificRegistrySuffix); | |
| 159 }; // class UserSpecificRegistrySuffix | |
| 160 | |
| 88 // This class represents a single registry entry. The objective is to | 161 // This class represents a single registry entry. The objective is to |
| 89 // encapsulate all the registry entries required for registering Chrome at one | 162 // encapsulate all the registry entries required for registering Chrome at one |
| 90 // place. This class can not be instantiated outside the class and the objects | 163 // place. This class can not be instantiated outside the class and the objects |
| 91 // of this class type can be obtained only by calling a static method of this | 164 // of this class type can be obtained only by calling a static method of this |
| 92 // class. | 165 // class. |
| 93 class RegistryEntry { | 166 class RegistryEntry { |
| 94 public: | 167 public: |
| 95 // A bit-field enum of places to look for this key in the Windows registry. | 168 // A bit-field enum of places to look for this key in the Windows registry. |
| 96 enum LookForIn { | 169 enum LookForIn { |
| 97 LOOK_IN_HKCU = 1 << 0, | 170 LOOK_IN_HKCU = 1 << 0, |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command | 247 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command |
| 175 entries->push_front(new RegistryEntry(sub_path, delegate_command)); | 248 entries->push_front(new RegistryEntry(sub_path, delegate_command)); |
| 176 entries->push_front(new RegistryEntry( | 249 entries->push_front(new RegistryEntry( |
| 177 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); | 250 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); |
| 178 } | 251 } |
| 179 } | 252 } |
| 180 | 253 |
| 181 // File association ProgId | 254 // File association ProgId |
| 182 string16 chrome_html_prog_id(ShellUtil::kRegClasses); | 255 string16 chrome_html_prog_id(ShellUtil::kRegClasses); |
| 183 chrome_html_prog_id.push_back(FilePath::kSeparators[0]); | 256 chrome_html_prog_id.push_back(FilePath::kSeparators[0]); |
| 184 chrome_html_prog_id.append(ShellUtil::kChromeHTMLProgId); | 257 chrome_html_prog_id.append(GetBrowserProgId(suffix)); |
| 185 chrome_html_prog_id.append(suffix); | |
| 186 entries->push_front(new RegistryEntry( | 258 entries->push_front(new RegistryEntry( |
| 187 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); | 259 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); |
| 188 entries->push_front(new RegistryEntry( | 260 entries->push_front(new RegistryEntry( |
| 189 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); | 261 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); |
| 190 entries->push_front(new RegistryEntry( | 262 entries->push_front(new RegistryEntry( |
| 191 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); | 263 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); |
| 192 entries->push_front(new RegistryEntry( | 264 entries->push_front(new RegistryEntry( |
| 193 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); | 265 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); |
| 194 if (set_delegate_execute) { | 266 if (set_delegate_execute) { |
| 195 entries->push_front(new RegistryEntry( | 267 entries->push_front(new RegistryEntry( |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 } | 299 } |
| 228 | 300 |
| 229 // This method returns a list of the registry entries needed to declare a | 301 // This method returns a list of the registry entries needed to declare a |
| 230 // capability of handling a protocol on Windows. | 302 // capability of handling a protocol on Windows. |
| 231 static bool GetProtocolCapabilityEntries(BrowserDistribution* dist, | 303 static bool GetProtocolCapabilityEntries(BrowserDistribution* dist, |
| 232 const string16& suffix, | 304 const string16& suffix, |
| 233 const string16& protocol, | 305 const string16& protocol, |
| 234 std::list<RegistryEntry*>* entries) { | 306 std::list<RegistryEntry*>* entries) { |
| 235 entries->push_front(new RegistryEntry( | 307 entries->push_front(new RegistryEntry( |
| 236 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), | 308 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), |
| 237 protocol, string16(ShellUtil::kChromeHTMLProgId).append(suffix))); | 309 protocol, GetBrowserProgId(suffix))); |
| 238 return true; | 310 return true; |
| 239 } | 311 } |
| 240 | 312 |
| 241 // This method returns a list of all the registry entries required to fully | 313 // This method returns a list of all the registry entries required to fully |
| 242 // integrate Chrome with Windows (i.e. StartMenuInternet, Default Programs, | 314 // integrate Chrome with Windows (i.e. StartMenuInternet, Default Programs, |
| 243 // AppPaths, etc.). This entries need to be registered in HKLM prior to Win8. | 315 // AppPaths, etc.). This entries need to be registered in HKLM prior to Win8. |
| 244 static bool GetShellIntegrationEntries(BrowserDistribution* dist, | 316 static bool GetShellIntegrationEntries(BrowserDistribution* dist, |
| 245 const string16& chrome_exe, | 317 const string16& chrome_exe, |
| 246 const string16& suffix, | 318 const string16& suffix, |
| 247 std::list<RegistryEntry*>* entries) { | 319 std::list<RegistryEntry*>* entries) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 dist->GetLongAppDescription())); | 360 dist->GetLongAppDescription())); |
| 289 entries->push_front(new RegistryEntry( | 361 entries->push_front(new RegistryEntry( |
| 290 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); | 362 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); |
| 291 entries->push_front(new RegistryEntry( | 363 entries->push_front(new RegistryEntry( |
| 292 capabilities, ShellUtil::kRegApplicationName, | 364 capabilities, ShellUtil::kRegApplicationName, |
| 293 dist->GetAppShortCutName())); | 365 dist->GetAppShortCutName())); |
| 294 | 366 |
| 295 entries->push_front(new RegistryEntry(capabilities + L"\\Startmenu", | 367 entries->push_front(new RegistryEntry(capabilities + L"\\Startmenu", |
| 296 L"StartMenuInternet", reg_app_name)); | 368 L"StartMenuInternet", reg_app_name)); |
| 297 | 369 |
| 298 string16 html_prog_id(ShellUtil::kChromeHTMLProgId); | 370 string16 html_prog_id(GetBrowserProgId(suffix)); |
| 299 html_prog_id.append(suffix); | |
| 300 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 371 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
| 301 entries->push_front(new RegistryEntry( | 372 entries->push_front(new RegistryEntry( |
| 302 capabilities + L"\\FileAssociations", | 373 capabilities + L"\\FileAssociations", |
| 303 ShellUtil::kFileAssociations[i], html_prog_id)); | 374 ShellUtil::kFileAssociations[i], html_prog_id)); |
| 304 } | 375 } |
| 305 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; | 376 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; |
| 306 i++) { | 377 i++) { |
| 307 entries->push_front(new RegistryEntry( | 378 entries->push_front(new RegistryEntry( |
| 308 capabilities + L"\\URLAssociations", | 379 capabilities + L"\\URLAssociations", |
| 309 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); | 380 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 return true; | 429 return true; |
| 359 } | 430 } |
| 360 | 431 |
| 361 // This method returns a list of all the user level registry entries that | 432 // This method returns a list of all the user level registry entries that |
| 362 // are needed to make Chromium default browser. | 433 // are needed to make Chromium default browser. |
| 363 static bool GetUserEntries(BrowserDistribution* dist, | 434 static bool GetUserEntries(BrowserDistribution* dist, |
| 364 const string16& chrome_exe, | 435 const string16& chrome_exe, |
| 365 const string16& suffix, | 436 const string16& suffix, |
| 366 std::list<RegistryEntry*>* entries) { | 437 std::list<RegistryEntry*>* entries) { |
| 367 // File extension associations. | 438 // File extension associations. |
| 368 string16 html_prog_id(ShellUtil::kChromeHTMLProgId); | 439 string16 html_prog_id(GetBrowserProgId(suffix)); |
| 369 html_prog_id.append(suffix); | |
| 370 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 440 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
| 371 string16 ext_key(ShellUtil::kRegClasses); | 441 string16 ext_key(ShellUtil::kRegClasses); |
| 372 ext_key.push_back(FilePath::kSeparators[0]); | 442 ext_key.push_back(FilePath::kSeparators[0]); |
| 373 ext_key.append(ShellUtil::kFileAssociations[i]); | 443 ext_key.append(ShellUtil::kFileAssociations[i]); |
| 374 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); | 444 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); |
| 375 } | 445 } |
| 376 | 446 |
| 377 // Protocols associations. | 447 // Protocols associations. |
| 378 string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | 448 string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
| 379 string16 chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe); | 449 string16 chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe); |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 670 | 740 |
| 671 // <root hkey>\Software\Classes\<app_id> | 741 // <root hkey>\Software\Classes\<app_id> |
| 672 string16 key(ShellUtil::kRegClasses); | 742 string16 key(ShellUtil::kRegClasses); |
| 673 key.push_back(FilePath::kSeparators[0]); | 743 key.push_back(FilePath::kSeparators[0]); |
| 674 key.append(app_id); | 744 key.append(app_id); |
| 675 InstallUtil::DeleteRegistryKey(root_key, key); | 745 InstallUtil::DeleteRegistryKey(root_key, key); |
| 676 | 746 |
| 677 // <root hkey>\Software\Classes\ChromiumHTML[.user]\shell\open\command | 747 // <root hkey>\Software\Classes\ChromiumHTML[.user]\shell\open\command |
| 678 key = ShellUtil::kRegClasses; | 748 key = ShellUtil::kRegClasses; |
| 679 key.push_back(FilePath::kSeparators[0]); | 749 key.push_back(FilePath::kSeparators[0]); |
| 680 key.append(ShellUtil::kChromeHTMLProgId); | 750 key.append(GetBrowserProgId(installation_suffix)); |
| 681 key.append(installation_suffix); | |
| 682 key.append(ShellUtil::kRegShellOpen); | 751 key.append(ShellUtil::kRegShellOpen); |
| 683 InstallUtil::DeleteRegistryValue(root_key, key, | 752 InstallUtil::DeleteRegistryValue(root_key, key, |
| 684 ShellUtil::kRegDelegateExecute); | 753 ShellUtil::kRegDelegateExecute); |
| 685 } | 754 } |
| 686 } | 755 } |
| 687 | 756 |
| 688 // Returns true if the current install's |chrome_exe| has been registered with | 757 // Returns true if the current install's |chrome_exe| has been registered with |
| 689 // |suffix|. | 758 // |suffix|. |
| 690 // |confirmation_level| is the level of verification desired as described in | 759 // |confirmation_level| is the level of verification desired as described in |
| 691 // the RegistrationConfirmationLevel enum above. | 760 // the RegistrationConfirmationLevel enum above. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 740 // Assert that |reg_key| points to |chrome_exe| in HKLM. | 809 // Assert that |reg_key| points to |chrome_exe| in HKLM. |
| 741 const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE); | 810 const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE); |
| 742 string16 hklm_value; | 811 string16 hklm_value; |
| 743 if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) { | 812 if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) { |
| 744 return InstallUtil::ProgramCompare( | 813 return InstallUtil::ProgramCompare( |
| 745 FilePath(chrome_exe)).Evaluate(hklm_value); | 814 FilePath(chrome_exe)).Evaluate(hklm_value); |
| 746 } | 815 } |
| 747 return false; | 816 return false; |
| 748 } | 817 } |
| 749 | 818 |
| 750 // Sets |suffix| to this user's username preceded by a dot. This suffix is then | 819 // Sets |suffix| to a 27 character string that is specific to this user on this |
| 751 // meant to be added to all registration that may conflict with another | 820 // machine (on user-level installs only). |
| 752 // user-level Chrome install. | 821 // To support old-style user-level installs however, |suffix| is cleared if the |
| 753 // Returns true unless the OS call to retrieve the username fails. | 822 // user currently owns the non-suffixed HKLM registrations. |
| 754 bool GetUserSpecificRegistrySuffix(string16* suffix) { | 823 // |suffix| can also be set to the user's username if the current install is |
| 755 wchar_t user_name[256]; | 824 // suffixed as per the old-style registrations. |
| 756 DWORD size = arraysize(user_name); | 825 // |suffix| is cleared on system-level installs. |
| 757 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
| 758 PLOG(DFATAL) << "GetUserName failed"; | |
| 759 return false; | |
| 760 } | |
| 761 suffix->reserve(size); | |
| 762 suffix->assign(1, L'.'); | |
| 763 suffix->append(user_name, size - 1); | |
| 764 return true; | |
| 765 } | |
| 766 | |
| 767 // Sets |suffix| to the current user's username, preceded by a dot, on | |
| 768 // user-level installs. | |
| 769 // To support old-style user-level installs however, |suffix| is cleared if | |
| 770 // the user currently owns the non-suffixed HKLM registrations. | |
| 771 // |suffix| is also cleared on system-level installs. | |
| 772 // |suffix| should then be appended to all Chrome properties that may conflict | 826 // |suffix| should then be appended to all Chrome properties that may conflict |
| 773 // with other Chrome user-level installs. | 827 // with other Chrome user-level installs. |
| 774 // Returns true unless one of the underlying calls fails. | 828 // Returns true unless one of the underlying calls fails. |
| 775 bool GetInstallationSpecificSuffix(BrowserDistribution* dist, | 829 bool GetInstallationSpecificSuffix(BrowserDistribution* dist, |
| 776 const string16& chrome_exe, | 830 const string16& chrome_exe, |
| 777 string16* suffix) { | 831 string16* suffix) { |
| 778 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || | 832 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || |
| 779 QuickIsChromeRegistered(dist, chrome_exe, string16(), | 833 QuickIsChromeRegistered(dist, chrome_exe, string16(), |
| 780 CONFIRM_SHELL_REGISTRATION)) { | 834 CONFIRM_SHELL_REGISTRATION)) { |
| 781 // No suffix on system-level installs and user-level installs already | 835 // No suffix on system-level installs and user-level installs already |
| 782 // registered with no suffix. | 836 // registered with no suffix. |
| 783 suffix->clear(); | 837 suffix->clear(); |
| 784 return true; | 838 return true; |
| 785 } else { | |
| 786 return GetUserSpecificRegistrySuffix(suffix); | |
| 787 } | 839 } |
| 840 | |
| 841 // Get the old suffix for the check below. | |
| 842 if (!ShellUtil::GetOldUserSpecificRegistrySuffix(suffix)) { | |
| 843 NOTREACHED(); | |
| 844 return false; | |
| 845 } | |
| 846 if (QuickIsChromeRegistered(dist, chrome_exe, *suffix, | |
| 847 CONFIRM_SHELL_REGISTRATION)) { | |
| 848 // Username suffix for installs that are suffixed as per the old-style. | |
| 849 return true; | |
| 850 } | |
| 851 | |
| 852 return ShellUtil::GetUserSpecificRegistrySuffix(suffix); | |
| 788 } | 853 } |
| 789 | 854 |
| 790 // Returns the root registry key (HKLM or HKCU) into which shell integration | 855 // Returns the root registry key (HKLM or HKCU) into which shell integration |
| 791 // registration for default protocols must be placed. As of Windows 8 everything | 856 // registration for default protocols must be placed. As of Windows 8 everything |
| 792 // can go in HKCU for per-user installs. | 857 // can go in HKCU for per-user installs. |
| 793 HKEY DetermineShellIntegrationRoot(bool is_per_user) { | 858 HKEY DetermineShellIntegrationRoot(bool is_per_user) { |
| 794 return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ? | 859 return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ? |
| 795 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; | 860 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; |
| 796 } | 861 } |
| 797 | 862 |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1053 key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS && | 1118 key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS && |
| 1054 !command.empty()) { | 1119 !command.empty()) { |
| 1055 (*browsers)[name] = command; | 1120 (*browsers)[name] = command; |
| 1056 } | 1121 } |
| 1057 } | 1122 } |
| 1058 } | 1123 } |
| 1059 } | 1124 } |
| 1060 | 1125 |
| 1061 string16 ShellUtil::GetCurrentInstallationSuffix(BrowserDistribution* dist, | 1126 string16 ShellUtil::GetCurrentInstallationSuffix(BrowserDistribution* dist, |
| 1062 const string16& chrome_exe) { | 1127 const string16& chrome_exe) { |
| 1128 // This method is somewhat the opposite of GetInstallationSpecificSuffix(). | |
| 1129 // In this case we are not trying to determine the current suffix for the | |
| 1130 // upcoming installation (i.e. not trying to stick to a currently bad | |
| 1131 // registration style if one is present). | |
| 1132 // Here we want to determine which suffix we should use at run-time. | |
| 1133 // In order of preference, we prefer (for user-level installs): | |
| 1134 // 1) Base 32 encoding of the md5 hash of the username (new-style). | |
| 1135 // 2) Username (old-style). | |
| 1136 // 3) Unsuffixed (even worse). | |
| 1063 string16 tested_suffix; | 1137 string16 tested_suffix; |
| 1064 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || | 1138 if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) && |
| 1065 !GetUserSpecificRegistrySuffix(&tested_suffix) || | 1139 (!GetUserSpecificRegistrySuffix(&tested_suffix) || |
| 1066 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, | 1140 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, |
| 1141 CONFIRM_PROGID_REGISTRATION)) && | |
| 1142 (!GetOldUserSpecificRegistrySuffix(&tested_suffix) || | |
| 1143 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, | |
| 1144 CONFIRM_PROGID_REGISTRATION)) && | |
| 1145 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix.erase(), | |
| 1067 CONFIRM_PROGID_REGISTRATION)) { | 1146 CONFIRM_PROGID_REGISTRATION)) { |
| 1068 return string16(); | 1147 // If Chrome is not registered under any of the possible suffixes (e.g. |
| 1148 // tests, Canary, etc.): use the new-style suffix at run-time. | |
| 1149 if (!GetUserSpecificRegistrySuffix(&tested_suffix)) | |
| 1150 NOTREACHED(); | |
| 1069 } | 1151 } |
| 1070 return tested_suffix; | 1152 return tested_suffix; |
| 1071 } | 1153 } |
| 1072 | 1154 |
| 1073 string16 ShellUtil::GetApplicationName(BrowserDistribution* dist, | 1155 string16 ShellUtil::GetApplicationName(BrowserDistribution* dist, |
| 1074 const string16& chrome_exe) { | 1156 const string16& chrome_exe) { |
| 1075 string16 app_name = dist->GetBaseAppName(); | 1157 string16 app_name = dist->GetBaseAppName(); |
| 1076 app_name += GetCurrentInstallationSuffix(dist, chrome_exe); | 1158 app_name += GetCurrentInstallationSuffix(dist, chrome_exe); |
| 1077 return app_name; | 1159 return app_name; |
| 1078 } | 1160 } |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1514 chrome_exe.c_str(), | 1596 chrome_exe.c_str(), |
| 1515 shortcut.c_str(), | 1597 shortcut.c_str(), |
| 1516 chrome_path.value().c_str(), | 1598 chrome_path.value().c_str(), |
| 1517 arguments.c_str(), | 1599 arguments.c_str(), |
| 1518 description.c_str(), | 1600 description.c_str(), |
| 1519 icon_path.c_str(), | 1601 icon_path.c_str(), |
| 1520 icon_index, | 1602 icon_index, |
| 1521 app_id.c_str(), | 1603 app_id.c_str(), |
| 1522 ConvertShellUtilShortcutOptionsToFileUtil(options)); | 1604 ConvertShellUtilShortcutOptionsToFileUtil(options)); |
| 1523 } | 1605 } |
| 1606 | |
| 1607 bool ShellUtil::GetUserSpecificRegistrySuffix(string16* suffix) { | |
| 1608 // Use a thread-safe cache for the user's suffix. | |
| 1609 static base::LazyInstance<UserSpecificRegistrySuffix>::Leaky suffix_instance = | |
| 1610 LAZY_INSTANCE_INITIALIZER; | |
| 1611 return suffix_instance.Get().GetSuffix(suffix); | |
| 1612 } | |
| 1613 | |
| 1614 bool ShellUtil::GetOldUserSpecificRegistrySuffix(string16* suffix) { | |
|
gab
2012/07/03 22:36:07
I thought of also caching this one in the UserSpec
grt (UTC plus 2)
2012/07/05 20:00:19
It could be done with a single class/instance owne
gab
2012/07/05 21:19:53
Right, GetUserName is probably very low-height (an
| |
| 1615 wchar_t user_name[256]; | |
| 1616 DWORD size = arraysize(user_name); | |
| 1617 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
| 1618 NOTREACHED(); | |
| 1619 return false; | |
| 1620 } | |
| 1621 suffix->reserve(size); | |
| 1622 suffix->assign(1, L'.'); | |
| 1623 suffix->append(user_name, size - 1); | |
| 1624 return true; | |
| 1625 } | |
| 1626 | |
| 1627 string16 ShellUtil::ByteArrayToBase32(const uint8* bytes, size_t size) { | |
| 1628 static const char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; | |
| 1629 | |
| 1630 // Eliminate special cases first. | |
| 1631 if (size == 0) { | |
| 1632 return string16(); | |
| 1633 } else if (size == 1) { | |
| 1634 string16 ret; | |
| 1635 ret.push_back(kEncoding[(bytes[0] & 0xf8) >> 3]); | |
| 1636 ret.push_back(kEncoding[(bytes[0] & 0x07) << 2]); | |
| 1637 return ret; | |
| 1638 } else if (size >= std::numeric_limits<size_t>::max() / 8) { | |
| 1639 // If |size| is too big, the calculation of |encoded_length| below will | |
| 1640 // overflow. | |
| 1641 NOTREACHED(); | |
| 1642 return string16(); | |
| 1643 } | |
| 1644 | |
| 1645 // Overestimate the number of bits in the string by 4 so that dividing by 5 | |
| 1646 // is the equivalent of rounding up the actual number of bits divided by 5. | |
| 1647 const size_t encoded_length = (size * 8 + 4) / 5; | |
| 1648 | |
| 1649 string16 ret; | |
| 1650 ret.reserve(encoded_length); | |
| 1651 | |
| 1652 // A bit stream which will be read from the left and appended to from the | |
| 1653 // right as it's emptied. | |
| 1654 uint16 bit_stream = (bytes[0] << 8) + bytes[1]; | |
| 1655 size_t next_byte_index = 2; | |
| 1656 int free_bits = 0; | |
| 1657 while (free_bits < 16) { | |
| 1658 // Extract the 5 leftmost bits in the stream | |
| 1659 ret.push_back(kEncoding[(bit_stream & 0xf800) >> 11]); | |
| 1660 bit_stream <<= 5; | |
| 1661 free_bits += 5; | |
| 1662 | |
| 1663 // If there is enough room in the bit stream, inject another byte (if there | |
| 1664 // are any left...). | |
| 1665 if (free_bits >= 8 && next_byte_index < size) { | |
| 1666 free_bits -= 8; | |
| 1667 bit_stream += bytes[next_byte_index++] << free_bits; | |
| 1668 } | |
| 1669 } | |
| 1670 | |
| 1671 DCHECK_EQ(ret.length(), encoded_length); | |
| 1672 return ret; | |
| 1673 } | |
| OLD | NEW |