| 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" |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 // Note: Shell registration implies ProgId registration. | 70 // Note: Shell registration implies ProgId registration. |
| 71 CONFIRM_SHELL_REGISTRATION, | 71 CONFIRM_SHELL_REGISTRATION, |
| 72 // Same as CONFIRM_SHELL_REGISTRATION, but only look in HKLM (used when | 72 // Same as CONFIRM_SHELL_REGISTRATION, but only look in HKLM (used when |
| 73 // uninstalling to know whether elevation is required to clean up the | 73 // uninstalling to know whether elevation is required to clean up the |
| 74 // registry). | 74 // registry). |
| 75 CONFIRM_SHELL_REGISTRATION_IN_HKLM, | 75 CONFIRM_SHELL_REGISTRATION_IN_HKLM, |
| 76 }; | 76 }; |
| 77 | 77 |
| 78 const wchar_t kReinstallCommand[] = L"ReinstallCommand"; | 78 const wchar_t kReinstallCommand[] = L"ReinstallCommand"; |
| 79 | 79 |
| 80 // Returns true if Chrome Metro is supported on this OS (Win 8 8370 or greater). | 80 // Returns true if Chrome Metro is supported on this version of Windows |
| 81 // TODO(gab): Change this to a simple check for Win 8 once old Win8 builds | 81 // (supported as of Win8; deprecated as of Win10). |
| 82 // become irrelevant. | |
| 83 bool IsChromeMetroSupported() { | 82 bool IsChromeMetroSupported() { |
| 84 OSVERSIONINFOEX min_version_info = {}; | 83 const base::win::Version win_version = base::win::GetVersion(); |
| 85 min_version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | 84 return win_version >= base::win::VERSION_WIN8 && |
| 86 min_version_info.dwMajorVersion = 6; | 85 win_version < base::win::VERSION_WIN10; |
| 87 min_version_info.dwMinorVersion = 2; | |
| 88 min_version_info.dwBuildNumber = 8370; | |
| 89 min_version_info.wServicePackMajor = 0; | |
| 90 min_version_info.wServicePackMinor = 0; | |
| 91 | |
| 92 DWORDLONG condition_mask = 0; | |
| 93 VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, VER_GREATER_EQUAL); | |
| 94 VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_GREATER_EQUAL); | |
| 95 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); | |
| 96 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); | |
| 97 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); | |
| 98 | |
| 99 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | | |
| 100 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; | |
| 101 | |
| 102 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; | |
| 103 } | 86 } |
| 104 | 87 |
| 105 // Returns the current (or installed) browser's ProgId (e.g. | 88 // Returns the current (or installed) browser's ProgId (e.g. |
| 106 // "ChromeHTML|suffix|"). | 89 // "ChromeHTML|suffix|"). |
| 107 // |suffix| can be the empty string. | 90 // |suffix| can be the empty string. |
| 108 base::string16 GetBrowserProgId(const base::string16& suffix) { | 91 base::string16 GetBrowserProgId(const base::string16& suffix) { |
| 109 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | 92 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 110 base::string16 chrome_html(dist->GetBrowserProgIdPrefix()); | 93 base::string16 chrome_html(dist->GetBrowserProgIdPrefix()); |
| 111 chrome_html.append(suffix); | 94 chrome_html.append(suffix); |
| 112 | 95 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 // class. | 168 // class. |
| 186 class RegistryEntry { | 169 class RegistryEntry { |
| 187 public: | 170 public: |
| 188 // A bit-field enum of places to look for this key in the Windows registry. | 171 // A bit-field enum of places to look for this key in the Windows registry. |
| 189 enum LookForIn { | 172 enum LookForIn { |
| 190 LOOK_IN_HKCU = 1 << 0, | 173 LOOK_IN_HKCU = 1 << 0, |
| 191 LOOK_IN_HKLM = 1 << 1, | 174 LOOK_IN_HKLM = 1 << 1, |
| 192 LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, | 175 LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, |
| 193 }; | 176 }; |
| 194 | 177 |
| 178 // Identifies the type of removal this RegistryEntry is flagged for, if any. |
| 179 enum class RemovalFlag { |
| 180 // Default case: install the key/value. |
| 181 NONE, |
| 182 // Registry value under |key_path_|\|name_| is flagged for deletion. |
| 183 VALUE, |
| 184 // Registry key under |key_path_| is flag for deletion. |
| 185 KEY, |
| 186 }; |
| 187 |
| 195 // Details about a Windows application, to be entered into the registry for | 188 // Details about a Windows application, to be entered into the registry for |
| 196 // the purpose of file associations. | 189 // the purpose of file associations. |
| 197 struct ApplicationInfo { | 190 struct ApplicationInfo { |
| 198 ApplicationInfo() : file_type_icon_index(0), application_icon_index(0) {} | 191 ApplicationInfo() : file_type_icon_index(0), application_icon_index(0) {} |
| 199 | 192 |
| 200 // The ProgId used by Windows for file associations with this application. | 193 // The ProgId used by Windows for file associations with this application. |
| 201 // Must not be empty or start with a '.'. | 194 // Must not be empty or start with a '.'. |
| 202 base::string16 prog_id; | 195 base::string16 prog_id; |
| 203 // The friendly name, and the path of the icon that will be used for files | 196 // The friendly name, and the path of the icon that will be used for files |
| 204 // of these types when associated with this application by default. (They | 197 // of these types when associated with this application by default. (They |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 } | 237 } |
| 245 | 238 |
| 246 // Returns the Windows Default Programs capabilities key for Chrome. For | 239 // Returns the Windows Default Programs capabilities key for Chrome. For |
| 247 // example: | 240 // example: |
| 248 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". | 241 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". |
| 249 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, | 242 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, |
| 250 const base::string16& suffix) { | 243 const base::string16& suffix) { |
| 251 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); | 244 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); |
| 252 } | 245 } |
| 253 | 246 |
| 247 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is |
| 248 // only needed for registring a web browser, not for general associations. |
| 249 static ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries( |
| 250 const base::FilePath& chrome_exe, |
| 251 const ApplicationInfo& app_info) { |
| 252 ScopedVector<RegistryEntry> entries; |
| 253 |
| 254 base::string16 app_id_shell_key(ShellUtil::kRegClasses); |
| 255 app_id_shell_key.push_back(base::FilePath::kSeparators[0]); |
| 256 app_id_shell_key.append(app_info.app_id); |
| 257 app_id_shell_key.append(ShellUtil::kRegExePath); |
| 258 app_id_shell_key.append(ShellUtil::kRegShellPath); |
| 259 |
| 260 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open |
| 261 entries.push_back( |
| 262 new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen)); |
| 263 |
| 264 // The command to execute when opening this application via the Metro UI. |
| 265 const base::string16 delegate_command( |
| 266 ShellUtil::GetChromeDelegateCommand(chrome_exe)); |
| 267 |
| 268 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is |
| 269 // registered to handle some verbs. This registration has the side-effect |
| 270 // that these verbs now show up in the shortcut's context menu. We |
| 271 // mitigate this side-effect by making the context menu entries |
| 272 // user readable/localized strings. See relevant MSDN article: |
| 273 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx |
| 274 static const struct { |
| 275 const wchar_t* verb; |
| 276 int name_id; |
| 277 } verbs[] = { |
| 278 {ShellUtil::kRegVerbOpen, -1}, |
| 279 {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE}, |
| 280 }; |
| 281 for (const auto& verb_and_id : verbs) { |
| 282 base::string16 sub_path(app_id_shell_key); |
| 283 sub_path.push_back(base::FilePath::kSeparators[0]); |
| 284 sub_path.append(verb_and_id.verb); |
| 285 |
| 286 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> |
| 287 if (verb_and_id.name_id != -1) { |
| 288 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
| 289 // resource. |
| 290 const base::string16 verb_name( |
| 291 installer::GetLocalizedString(verb_and_id.name_id)); |
| 292 entries.push_back(new RegistryEntry(sub_path, verb_name.c_str())); |
| 293 } |
| 294 entries.push_back( |
| 295 new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch")); |
| 296 |
| 297 sub_path.push_back(base::FilePath::kSeparators[0]); |
| 298 sub_path.append(ShellUtil::kRegCommand); |
| 299 |
| 300 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command |
| 301 entries.push_back(new RegistryEntry(sub_path, delegate_command)); |
| 302 entries.push_back(new RegistryEntry( |
| 303 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid)); |
| 304 } |
| 305 |
| 306 return entries.Pass(); |
| 307 } |
| 308 |
| 254 // This method returns a list of all the registry entries that | 309 // This method returns a list of all the registry entries that |
| 255 // are needed to register this installation's ProgId and AppId. | 310 // are needed to register this installation's ProgId and AppId. |
| 256 // These entries need to be registered in HKLM prior to Win8. | 311 // These entries need to be registered in HKLM prior to Win8. |
| 257 static void GetChromeProgIdEntries(BrowserDistribution* dist, | 312 static void GetChromeProgIdEntries(BrowserDistribution* dist, |
| 258 const base::FilePath& chrome_exe, | 313 const base::FilePath& chrome_exe, |
| 259 const base::string16& suffix, | 314 const base::string16& suffix, |
| 260 ScopedVector<RegistryEntry>* entries) { | 315 ScopedVector<RegistryEntry>* entries) { |
| 261 int chrome_icon_index = | 316 int chrome_icon_index = |
| 262 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME); | 317 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME); |
| 263 | 318 |
| 264 ApplicationInfo app_info; | 319 ApplicationInfo app_info; |
| 265 app_info.prog_id = GetBrowserProgId(suffix); | 320 app_info.prog_id = GetBrowserProgId(suffix); |
| 266 app_info.file_type_name = dist->GetBrowserProgIdDesc(); | 321 app_info.file_type_name = dist->GetBrowserProgIdDesc(); |
| 267 // File types associated with Chrome are just given the Chrome icon. | 322 // File types associated with Chrome are just given the Chrome icon. |
| 268 app_info.file_type_icon_path = chrome_exe; | 323 app_info.file_type_icon_path = chrome_exe; |
| 269 app_info.file_type_icon_index = chrome_icon_index; | 324 app_info.file_type_icon_index = chrome_icon_index; |
| 270 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | 325 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
| 271 // For user-level installs: entries for the app id will be in HKCU; thus we | 326 // For user-level installs: entries for the app id will be in HKCU; thus we |
| 272 // do not need a suffix on those entries. | 327 // do not need a suffix on those entries. |
| 273 app_info.app_id = ShellUtil::GetBrowserModelId( | 328 app_info.app_id = ShellUtil::GetBrowserModelId( |
| 274 dist, InstallUtil::IsPerUserInstall(chrome_exe)); | 329 dist, InstallUtil::IsPerUserInstall(chrome_exe)); |
| 275 | 330 |
| 276 // The command to execute when opening this application via the Metro UI. | |
| 277 base::string16 delegate_command( | |
| 278 ShellUtil::GetChromeDelegateCommand(chrome_exe)); | |
| 279 bool set_delegate_execute = | |
| 280 IsChromeMetroSupported() && | |
| 281 dist->GetCommandExecuteImplClsid(&app_info.delegate_clsid); | |
| 282 | |
| 283 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | 331 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
| 284 // resource for name, description, and company. | 332 // resource for name, description, and company. |
| 285 app_info.application_name = dist->GetDisplayName(); | 333 app_info.application_name = dist->GetDisplayName(); |
| 286 app_info.application_icon_path = chrome_exe; | 334 app_info.application_icon_path = chrome_exe; |
| 287 app_info.application_icon_index = chrome_icon_index; | 335 app_info.application_icon_index = chrome_icon_index; |
| 288 app_info.application_description = dist->GetAppDescription(); | 336 app_info.application_description = dist->GetAppDescription(); |
| 289 app_info.publisher_name = dist->GetPublisherName(); | 337 app_info.publisher_name = dist->GetPublisherName(); |
| 290 | 338 |
| 339 dist->GetCommandExecuteImplClsid(&app_info.delegate_clsid); |
| 340 |
| 291 GetProgIdEntries(app_info, entries); | 341 GetProgIdEntries(app_info, entries); |
| 292 | 342 |
| 293 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is | 343 if (!app_info.delegate_clsid.empty()) { |
| 294 // only needed for registring a web browser, not for general associations. | 344 ScopedVector<RegistryEntry> delegate_execute_entries = |
| 295 if (set_delegate_execute) { | 345 GetChromeDelegateExecuteEntries(chrome_exe, app_info); |
| 296 base::string16 model_id_shell(ShellUtil::kRegClasses); | 346 if (!IsChromeMetroSupported()) { |
| 297 model_id_shell.push_back(base::FilePath::kSeparators[0]); | 347 // Remove the keys (not only their values) so that Windows will continue |
| 298 model_id_shell.append(app_info.app_id); | 348 // to launch Chrome without a pesky association error. |
| 299 model_id_shell.append(ShellUtil::kRegExePath); | 349 for (RegistryEntry* entry : delegate_execute_entries) |
| 300 model_id_shell.append(ShellUtil::kRegShellPath); | 350 entry->set_removal_flag(RemovalFlag::KEY); |
| 301 | |
| 302 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open | |
| 303 entries->push_back(new RegistryEntry(model_id_shell, | |
| 304 ShellUtil::kRegVerbOpen)); | |
| 305 | |
| 306 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is | |
| 307 // registered to handle some verbs. This registration has the side-effect | |
| 308 // that these verbs now show up in the shortcut's context menu. We | |
| 309 // mitigate this side-effect by making the context menu entries | |
| 310 // user readable/localized strings. See relevant MSDN article: | |
| 311 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx | |
| 312 const struct { | |
| 313 const wchar_t* verb; | |
| 314 int name_id; | |
| 315 } verbs[] = { | |
| 316 { ShellUtil::kRegVerbOpen, -1 }, | |
| 317 { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE }, | |
| 318 }; | |
| 319 for (size_t i = 0; i < arraysize(verbs); ++i) { | |
| 320 base::string16 sub_path(model_id_shell); | |
| 321 sub_path.push_back(base::FilePath::kSeparators[0]); | |
| 322 sub_path.append(verbs[i].verb); | |
| 323 | |
| 324 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> | |
| 325 if (verbs[i].name_id != -1) { | |
| 326 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | |
| 327 // resource. | |
| 328 base::string16 verb_name( | |
| 329 installer::GetLocalizedString(verbs[i].name_id)); | |
| 330 entries->push_back(new RegistryEntry(sub_path, verb_name.c_str())); | |
| 331 } | |
| 332 entries->push_back(new RegistryEntry( | |
| 333 sub_path, L"CommandId", L"Browser.Launch")); | |
| 334 | |
| 335 sub_path.push_back(base::FilePath::kSeparators[0]); | |
| 336 sub_path.append(ShellUtil::kRegCommand); | |
| 337 | |
| 338 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command | |
| 339 entries->push_back(new RegistryEntry(sub_path, delegate_command)); | |
| 340 entries->push_back(new RegistryEntry( | |
| 341 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid)); | |
| 342 } | 351 } |
| 352 // Move |delegate_execute_entries| to |entries|. |
| 353 entries->insert(entries->end(), delegate_execute_entries.begin(), |
| 354 delegate_execute_entries.end()); |
| 355 delegate_execute_entries.weak_clear(); |
| 343 } | 356 } |
| 344 } | 357 } |
| 345 | 358 |
| 346 // Gets the registry entries to register an application in the Windows | 359 // Gets the registry entries to register an application in the Windows |
| 347 // registry. |app_info| provides all of the information needed. | 360 // registry. |app_info| provides all of the information needed. |
| 348 static void GetProgIdEntries(const ApplicationInfo& app_info, | 361 static void GetProgIdEntries(const ApplicationInfo& app_info, |
| 349 ScopedVector<RegistryEntry>* entries) { | 362 ScopedVector<RegistryEntry>* entries) { |
| 350 // Basic sanity checks. | 363 // Basic sanity checks. |
| 351 DCHECK(!app_info.prog_id.empty()); | 364 DCHECK(!app_info.prog_id.empty()); |
| 352 DCHECK_NE(L'.', app_info.prog_id[0]); | 365 DCHECK_NE(L'.', app_info.prog_id[0]); |
| 353 | 366 |
| 354 // File association ProgId | 367 // File association ProgId |
| 355 base::string16 prog_id_path(ShellUtil::kRegClasses); | 368 base::string16 prog_id_path(ShellUtil::kRegClasses); |
| 356 prog_id_path.push_back(base::FilePath::kSeparators[0]); | 369 prog_id_path.push_back(base::FilePath::kSeparators[0]); |
| 357 prog_id_path.append(app_info.prog_id); | 370 prog_id_path.append(app_info.prog_id); |
| 358 entries->push_back( | 371 entries->push_back( |
| 359 new RegistryEntry(prog_id_path, app_info.file_type_name)); | 372 new RegistryEntry(prog_id_path, app_info.file_type_name)); |
| 360 entries->push_back(new RegistryEntry( | 373 entries->push_back(new RegistryEntry( |
| 361 prog_id_path + ShellUtil::kRegDefaultIcon, | 374 prog_id_path + ShellUtil::kRegDefaultIcon, |
| 362 ShellUtil::FormatIconLocation(app_info.file_type_icon_path, | 375 ShellUtil::FormatIconLocation(app_info.file_type_icon_path, |
| 363 app_info.file_type_icon_index))); | 376 app_info.file_type_icon_index))); |
| 364 entries->push_back(new RegistryEntry( | 377 entries->push_back(new RegistryEntry( |
| 365 prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line)); | 378 prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line)); |
| 366 if (!app_info.delegate_clsid.empty()) { | 379 if (!app_info.delegate_clsid.empty()) { |
| 367 entries->push_back( | 380 entries->push_back( |
| 368 new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen, | 381 new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen, |
| 369 ShellUtil::kRegDelegateExecute, | 382 ShellUtil::kRegDelegateExecute, |
| 370 app_info.delegate_clsid)); | 383 app_info.delegate_clsid)); |
| 384 // If Metro is not supported, remove the DelegateExecute entry instead of |
| 385 // adding it. |
| 386 if (!IsChromeMetroSupported()) |
| 387 entries->back()->set_removal_flag(RemovalFlag::VALUE); |
| 371 } | 388 } |
| 372 | 389 |
| 373 // The following entries are required as of Windows 8, but do not | 390 // The following entries are required as of Windows 8, but do not |
| 374 // depend on the DelegateExecute verb handler being set. | 391 // depend on the DelegateExecute verb handler being set. |
| 375 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { | 392 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { |
| 376 if (!app_info.app_id.empty()) { | 393 if (!app_info.app_id.empty()) { |
| 377 entries->push_back(new RegistryEntry( | 394 entries->push_back(new RegistryEntry( |
| 378 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); | 395 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); |
| 379 } | 396 } |
| 380 | 397 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], | 656 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], |
| 640 chrome_icon, chrome_open, entries); | 657 chrome_icon, chrome_open, entries); |
| 641 } | 658 } |
| 642 | 659 |
| 643 // start->Internet shortcut. | 660 // start->Internet shortcut. |
| 644 base::string16 start_menu(ShellUtil::kRegStartMenuInternet); | 661 base::string16 start_menu(ShellUtil::kRegStartMenuInternet); |
| 645 base::string16 app_name = dist->GetBaseAppName() + suffix; | 662 base::string16 app_name = dist->GetBaseAppName() + suffix; |
| 646 entries->push_back(new RegistryEntry(start_menu, app_name)); | 663 entries->push_back(new RegistryEntry(start_menu, app_name)); |
| 647 } | 664 } |
| 648 | 665 |
| 649 // Generate work_item tasks required to create current registry entry and | 666 // Flags this RegistryKey with |removal_flag|, indicating that it should be |
| 650 // add them to the given work item list. | 667 // removed rather than created. Note that this will not result in cleaning up |
| 668 // the entire registry hierarchy below RegistryEntry even if it is left empty |
| 669 // by this operation (this should thus not be used for uninstall, but only to |
| 670 // unregister keys that should explicitly no longer be active in the current |
| 671 // configuration). |
| 672 void set_removal_flag(RemovalFlag removal_flag) { |
| 673 removal_flag_ = removal_flag; |
| 674 } |
| 675 |
| 676 // Generates work_item tasks required to create (or potentially delete based |
| 677 // on |removal_flag_|) the current RegistryEntry and add them to the given |
| 678 // work item list. |
| 651 void AddToWorkItemList(HKEY root, WorkItemList *items) const { | 679 void AddToWorkItemList(HKEY root, WorkItemList *items) const { |
| 652 items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); | 680 if (removal_flag_ == RemovalFlag::VALUE) { |
| 653 if (is_string_) { | 681 items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, |
| 654 items->AddSetRegValueWorkItem( | 682 name_); |
| 655 root, key_path_, WorkItem::kWow64Default, name_, value_, true); | 683 } else if (removal_flag_ == RemovalFlag::KEY) { |
| 684 items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); |
| 656 } else { | 685 } else { |
| 657 items->AddSetRegValueWorkItem( | 686 DCHECK(removal_flag_ == RemovalFlag::NONE); |
| 658 root, key_path_, WorkItem::kWow64Default, name_, int_value_, true); | 687 items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); |
| 688 if (is_string_) { |
| 689 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, |
| 690 name_, value_, true); |
| 691 } else { |
| 692 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, |
| 693 name_, int_value_, true); |
| 694 } |
| 659 } | 695 } |
| 660 } | 696 } |
| 661 | 697 |
| 698 // Returns true if this key is flagged for removal. |
| 699 bool IsFlaggedForRemoval() const { |
| 700 return removal_flag_ != RemovalFlag::NONE; |
| 701 } |
| 702 |
| 662 // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| | 703 // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| |
| 663 // and value is |value_|. If the key does NOT exist in HKCU, checks for | 704 // and value is |value_|. If the key does NOT exist in HKCU, checks for |
| 664 // the correct name and value in HKLM. | 705 // the correct name and value in HKLM. |
| 665 // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the | 706 // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the |
| 666 // key, unspecified roots are not looked into (i.e. the the key is assumed not | 707 // key, unspecified roots are not looked into (i.e. the the key is assumed not |
| 667 // to exist in them). | 708 // to exist in them). |
| 668 // |look_for_in| must at least specify one root to look into. | 709 // |look_for_in| must at least specify one root to look into. |
| 669 // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' | 710 // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' |
| 670 // behavior when searching in HKCR (HKCU takes precedence over HKLM). For | 711 // behavior when searching in HKCR (HKCU takes precedence over HKLM). For |
| 671 // registrations outside of HKCR on versions of Windows prior to Win8, | 712 // registrations outside of HKCR on versions of Windows prior to Win8, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 // |name_| does not exist in the registry | 744 // |name_| does not exist in the registry |
| 704 DOES_NOT_EXIST, | 745 DOES_NOT_EXIST, |
| 705 // |name_| exists, but its value != |value_| | 746 // |name_| exists, but its value != |value_| |
| 706 DIFFERENT_VALUE, | 747 DIFFERENT_VALUE, |
| 707 // |name_| exists and its value is |value_| | 748 // |name_| exists and its value is |value_| |
| 708 SAME_VALUE, | 749 SAME_VALUE, |
| 709 }; | 750 }; |
| 710 | 751 |
| 711 // Create a object that represent default value of a key | 752 // Create a object that represent default value of a key |
| 712 RegistryEntry(const base::string16& key_path, const base::string16& value) | 753 RegistryEntry(const base::string16& key_path, const base::string16& value) |
| 713 : key_path_(key_path), name_(), | 754 : key_path_(key_path), |
| 714 is_string_(true), value_(value), int_value_(0) { | 755 name_(), |
| 715 } | 756 is_string_(true), |
| 757 value_(value), |
| 758 int_value_(0), |
| 759 removal_flag_(RemovalFlag::NONE) {} |
| 716 | 760 |
| 717 // Create a object that represent a key of type REG_SZ | 761 // Create a object that represent a key of type REG_SZ |
| 718 RegistryEntry(const base::string16& key_path, const base::string16& name, | 762 RegistryEntry(const base::string16& key_path, |
| 763 const base::string16& name, |
| 719 const base::string16& value) | 764 const base::string16& value) |
| 720 : key_path_(key_path), name_(name), | 765 : key_path_(key_path), |
| 721 is_string_(true), value_(value), int_value_(0) { | 766 name_(name), |
| 722 } | 767 is_string_(true), |
| 768 value_(value), |
| 769 int_value_(0), |
| 770 removal_flag_(RemovalFlag::NONE) {} |
| 723 | 771 |
| 724 // Create a object that represent a key of integer type | 772 // Create a object that represent a key of integer type |
| 725 RegistryEntry(const base::string16& key_path, const base::string16& name, | 773 RegistryEntry(const base::string16& key_path, |
| 774 const base::string16& name, |
| 726 DWORD value) | 775 DWORD value) |
| 727 : key_path_(key_path), name_(name), | 776 : key_path_(key_path), |
| 728 is_string_(false), value_(), int_value_(value) { | 777 name_(name), |
| 729 } | 778 is_string_(false), |
| 779 value_(), |
| 780 int_value_(value), |
| 781 removal_flag_(RemovalFlag::NONE) {} |
| 730 | 782 |
| 731 base::string16 key_path_; // key path for the registry entry | 783 base::string16 key_path_; // key path for the registry entry |
| 732 base::string16 name_; // name of the registry entry | 784 base::string16 name_; // name of the registry entry |
| 733 bool is_string_; // true if current registry entry is of type REG_SZ | 785 bool is_string_; // true if current registry entry is of type REG_SZ |
| 734 base::string16 value_; // string value (useful if is_string_ = true) | 786 base::string16 value_; // string value (useful if is_string_ = true) |
| 735 DWORD int_value_; // integer value (useful if is_string_ = false) | 787 DWORD int_value_; // integer value (useful if is_string_ = false) |
| 736 | 788 |
| 789 // Identifies whether this RegistryEntry is flagged for removal (i.e. no |
| 790 // longer relevant on the configuration it was created under). |
| 791 RemovalFlag removal_flag_; |
| 792 |
| 737 // Helper function for ExistsInRegistry(). | 793 // Helper function for ExistsInRegistry(). |
| 738 // Returns the RegistryStatus of the current registry entry in | 794 // Returns the RegistryStatus of the current registry entry in |
| 739 // |root|\|key_path_|\|name_|. | 795 // |root|\|key_path_|\|name_|. |
| 740 RegistryStatus StatusInRegistryUnderRoot(HKEY root) const { | 796 RegistryStatus StatusInRegistryUnderRoot(HKEY root) const { |
| 741 RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE); | 797 RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE); |
| 742 bool found = false; | 798 bool found = false; |
| 743 bool correct_value = false; | 799 bool correct_value = false; |
| 744 if (is_string_) { | 800 if (is_string_) { |
| 745 base::string16 read_value; | 801 base::string16 read_value; |
| 746 found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS; | 802 found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 777 (*itr)->AddToWorkItemList(root, items.get()); | 833 (*itr)->AddToWorkItemList(root, items.get()); |
| 778 | 834 |
| 779 // Apply all the registry changes and if there is a problem, rollback | 835 // Apply all the registry changes and if there is a problem, rollback |
| 780 if (!items->Do()) { | 836 if (!items->Do()) { |
| 781 items->Rollback(); | 837 items->Rollback(); |
| 782 return false; | 838 return false; |
| 783 } | 839 } |
| 784 return true; | 840 return true; |
| 785 } | 841 } |
| 786 | 842 |
| 787 // Checks that all |entries| are present on this computer. | 843 // Checks that all |entries| are present on this computer (or absent if their |
| 788 // |look_for_in| is passed to RegistryEntry::ExistsInRegistry(). Documentation | 844 // |removal_flag_| is set). |look_for_in| is passed to |
| 789 // for it can be found there. | 845 // RegistryEntry::ExistsInRegistry(). Documentation for it can be found there. |
| 790 bool AreEntriesRegistered(const ScopedVector<RegistryEntry>& entries, | 846 bool AreEntriesAsDesired(const ScopedVector<RegistryEntry>& entries, |
| 791 uint32 look_for_in) { | 847 uint32 look_for_in) { |
| 792 bool registered = true; | 848 for (const auto* entry : entries) { |
| 793 for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin(); | 849 if (entry->ExistsInRegistry(look_for_in) != !entry->IsFlaggedForRemoval()) |
| 794 registered && itr != entries.end(); ++itr) { | 850 return false; |
| 795 // We do not need registered = registered && ... since the loop condition | |
| 796 // is set to exit early. | |
| 797 registered = (*itr)->ExistsInRegistry(look_for_in); | |
| 798 } | 851 } |
| 799 return registered; | 852 return true; |
| 800 } | 853 } |
| 801 | 854 |
| 802 // Checks that all required registry entries for Chrome are already present | 855 // Checks that all required registry entries for Chrome are already present on |
| 803 // on this computer. See RegistryEntry::ExistsInRegistry for the behavior of | 856 // this computer (or absent if their |removal_flag_| is set). |
| 804 // |look_for_in|. | 857 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|. |
| 805 // Note: between r133333 and r154145 we were registering parts of Chrome in HKCU | 858 // Note: between r133333 and r154145 we were registering parts of Chrome in HKCU |
| 806 // and parts in HKLM for user-level installs; we now always register everything | 859 // and parts in HKLM for user-level installs; we now always register everything |
| 807 // under a single registry root. Not doing so caused http://crbug.com/144910 for | 860 // under a single registry root. Not doing so caused http://crbug.com/144910 for |
| 808 // users who first-installed Chrome in that revision range (those users are | 861 // users who first-installed Chrome in that revision range (those users are |
| 809 // still impacted by http://crbug.com/144910). This method will keep returning | 862 // still impacted by http://crbug.com/144910). This method will keep returning |
| 810 // true for affected users (i.e. who have all the registrations, but over both | 863 // true for affected users (i.e. who have all the registrations, but over both |
| 811 // registry roots). | 864 // registry roots). |
| 812 bool IsChromeRegistered(BrowserDistribution* dist, | 865 bool IsChromeRegistered(BrowserDistribution* dist, |
| 813 const base::FilePath& chrome_exe, | 866 const base::FilePath& chrome_exe, |
| 814 const base::string16& suffix, | 867 const base::string16& suffix, |
| 815 uint32 look_for_in) { | 868 uint32 look_for_in) { |
| 816 ScopedVector<RegistryEntry> entries; | 869 ScopedVector<RegistryEntry> entries; |
| 817 RegistryEntry::GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); | 870 RegistryEntry::GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); |
| 818 RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries); | 871 RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries); |
| 819 RegistryEntry::GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); | 872 RegistryEntry::GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); |
| 820 return AreEntriesRegistered(entries, look_for_in); | 873 return AreEntriesAsDesired(entries, look_for_in); |
| 821 } | 874 } |
| 822 | 875 |
| 823 // This method checks if Chrome is already registered on the local machine | 876 // This method checks if Chrome is already registered on the local machine |
| 824 // for the requested protocol. It just checks the one value required for this. | 877 // for the requested protocol. It just checks the one value required for this. |
| 825 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|. | 878 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|. |
| 826 bool IsChromeRegisteredForProtocol(BrowserDistribution* dist, | 879 bool IsChromeRegisteredForProtocol(BrowserDistribution* dist, |
| 827 const base::string16& suffix, | 880 const base::string16& suffix, |
| 828 const base::string16& protocol, | 881 const base::string16& protocol, |
| 829 uint32 look_for_in) { | 882 uint32 look_for_in) { |
| 830 ScopedVector<RegistryEntry> entries; | 883 ScopedVector<RegistryEntry> entries; |
| 831 RegistryEntry::GetProtocolCapabilityEntries(dist, suffix, protocol, &entries); | 884 RegistryEntry::GetProtocolCapabilityEntries(dist, suffix, protocol, &entries); |
| 832 return AreEntriesRegistered(entries, look_for_in); | 885 return AreEntriesAsDesired(entries, look_for_in); |
| 833 } | 886 } |
| 834 | 887 |
| 835 // This method registers Chrome on Vista by launching an elevated setup.exe. | 888 // This method registers Chrome on Vista by launching an elevated setup.exe. |
| 836 // That will show the user the standard Vista elevation prompt. If the user | 889 // That will show the user the standard Vista elevation prompt. If the user |
| 837 // accepts it the new process will make the necessary changes and return SUCCESS | 890 // accepts it the new process will make the necessary changes and return SUCCESS |
| 838 // that we capture and return. | 891 // that we capture and return. |
| 839 // If protocol is non-empty we will also register Chrome as being capable of | 892 // If protocol is non-empty we will also register Chrome as being capable of |
| 840 // handling the protocol. | 893 // handling the protocol. |
| 841 bool ElevateAndRegisterChrome(BrowserDistribution* dist, | 894 bool ElevateAndRegisterChrome(BrowserDistribution* dist, |
| 842 const base::FilePath& chrome_exe, | 895 const base::FilePath& chrome_exe, |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1148 if (properties.has_dual_mode()) | 1201 if (properties.has_dual_mode()) |
| 1149 shortcut_properties.set_dual_mode(properties.dual_mode); | 1202 shortcut_properties.set_dual_mode(properties.dual_mode); |
| 1150 | 1203 |
| 1151 return shortcut_properties; | 1204 return shortcut_properties; |
| 1152 } | 1205 } |
| 1153 | 1206 |
| 1154 // Cleans up an old verb (run) we used to register in | 1207 // Cleans up an old verb (run) we used to register in |
| 1155 // <root>\Software\Classes\Chrome<.suffix>\.exe\shell\run on Windows 8. | 1208 // <root>\Software\Classes\Chrome<.suffix>\.exe\shell\run on Windows 8. |
| 1156 void RemoveRunVerbOnWindows8(BrowserDistribution* dist, | 1209 void RemoveRunVerbOnWindows8(BrowserDistribution* dist, |
| 1157 const base::FilePath& chrome_exe) { | 1210 const base::FilePath& chrome_exe) { |
| 1158 if (IsChromeMetroSupported()) { | 1211 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { |
| 1159 bool is_per_user_install = InstallUtil::IsPerUserInstall(chrome_exe); | 1212 bool is_per_user_install = InstallUtil::IsPerUserInstall(chrome_exe); |
| 1160 HKEY root_key = DetermineRegistrationRoot(is_per_user_install); | 1213 HKEY root_key = DetermineRegistrationRoot(is_per_user_install); |
| 1161 // There's no need to rollback, so forgo the usual work item lists and just | 1214 // There's no need to rollback, so forgo the usual work item lists and just |
| 1162 // remove the key from the registry. | 1215 // remove the key from the registry. |
| 1163 base::string16 run_verb_key(ShellUtil::kRegClasses); | 1216 base::string16 run_verb_key(ShellUtil::kRegClasses); |
| 1164 run_verb_key.push_back(base::FilePath::kSeparators[0]); | 1217 run_verb_key.push_back(base::FilePath::kSeparators[0]); |
| 1165 run_verb_key.append(ShellUtil::GetBrowserModelId( | 1218 run_verb_key.append(ShellUtil::GetBrowserModelId( |
| 1166 dist, is_per_user_install)); | 1219 dist, is_per_user_install)); |
| 1167 run_verb_key.append(ShellUtil::kRegExePath); | 1220 run_verb_key.append(ShellUtil::kRegExePath); |
| 1168 run_verb_key.append(ShellUtil::kRegShellPath); | 1221 run_verb_key.append(ShellUtil::kRegShellPath); |
| (...skipping 1082 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2251 } else { | 2304 } else { |
| 2252 // If we got to this point then all we can do is create ProgId and basic app | 2305 // If we got to this point then all we can do is create ProgId and basic app |
| 2253 // registrations under HKCU. | 2306 // registrations under HKCU. |
| 2254 ScopedVector<RegistryEntry> entries; | 2307 ScopedVector<RegistryEntry> entries; |
| 2255 RegistryEntry::GetChromeProgIdEntries( | 2308 RegistryEntry::GetChromeProgIdEntries( |
| 2256 dist, chrome_exe, base::string16(), &entries); | 2309 dist, chrome_exe, base::string16(), &entries); |
| 2257 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered | 2310 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered |
| 2258 // with no suffix (as per the old registration style): in which case some | 2311 // with no suffix (as per the old registration style): in which case some |
| 2259 // other registry entries could refer to them and since we were not able to | 2312 // other registry entries could refer to them and since we were not able to |
| 2260 // set our HKLM entries above, we are better off not altering these here. | 2313 // set our HKLM entries above, we are better off not altering these here. |
| 2261 if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) { | 2314 if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) { |
| 2262 if (!suffix.empty()) { | 2315 if (!suffix.empty()) { |
| 2263 entries.clear(); | 2316 entries.clear(); |
| 2264 RegistryEntry::GetChromeProgIdEntries( | 2317 RegistryEntry::GetChromeProgIdEntries( |
| 2265 dist, chrome_exe, suffix, &entries); | 2318 dist, chrome_exe, suffix, &entries); |
| 2266 RegistryEntry::GetChromeAppRegistrationEntries( | 2319 RegistryEntry::GetChromeAppRegistrationEntries( |
| 2267 chrome_exe, suffix, &entries); | 2320 chrome_exe, suffix, &entries); |
| 2268 } | 2321 } |
| 2269 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | 2322 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); |
| 2270 } else { | 2323 } else { |
| 2271 // The ProgId is registered unsuffixed in HKCU, also register the app with | 2324 // The ProgId is registered unsuffixed in HKCU, also register the app with |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2512 base::string16 key_path(ShellUtil::kRegClasses); | 2565 base::string16 key_path(ShellUtil::kRegClasses); |
| 2513 key_path.push_back(base::FilePath::kSeparators[0]); | 2566 key_path.push_back(base::FilePath::kSeparators[0]); |
| 2514 key_path.append(prog_id); | 2567 key_path.append(prog_id); |
| 2515 return InstallUtil::DeleteRegistryKey( | 2568 return InstallUtil::DeleteRegistryKey( |
| 2516 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default); | 2569 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default); |
| 2517 | 2570 |
| 2518 // TODO(mgiuca): Remove the extension association entries. This requires that | 2571 // TODO(mgiuca): Remove the extension association entries. This requires that |
| 2519 // the extensions associated with a particular prog_id are stored in that | 2572 // the extensions associated with a particular prog_id are stored in that |
| 2520 // prog_id's key. | 2573 // prog_id's key. |
| 2521 } | 2574 } |
| OLD | NEW |